From 61c2398b6741667b11fb3ab2d6f0dc718635ca36 Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Sat, 10 Jul 2021 01:17:38 +0200
Subject: [PATCH 1/8] readme: fix lto option

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 759993a1..0bfd955b 100644
--- a/README.md
+++ b/README.md
@@ -130,7 +130,7 @@ Microsoft recently discontinued its downloads of the DX9 SDK. You can download a
 **If you choose OpenAL on Windows** You must read [Running OpenAL build on Windows](https://github.com/GTAmodding/re3/wiki/Running-OpenAL-build-on-Windows).
 </details>
 
-> :information_source: premake has an `--lto` option if you want the project to be compiled with Link Time Optimization.
+> :information_source: premake has an `--with-lto` option if you want the project to be compiled with Link Time Optimization.
 
 > :information_source: There are various settings in [config.h](https://github.com/GTAmodding/re3/tree/miami/src/core/config.h), you may want to take a look there.
 

From 6f103a3b8246ed4a883abaea63c6682cdefc6752 Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Wed, 7 Jul 2021 17:34:02 +0200
Subject: [PATCH 2/8] finish COMPATIBLE_SAVES and FIX_INCOMPATIBLE_SAVES

---
 src/control/AutoPilot.cpp       |  66 ++--
 src/control/Garages.cpp         | 127 ++++++--
 src/control/Garages.h           |  15 +-
 src/control/Phones.cpp          |  33 +-
 src/control/Pickups.cpp         |  58 +++-
 src/control/Script5.cpp         |  36 +--
 src/core/Placeable.h            |   2 +-
 src/core/Pools.cpp              |  12 +-
 src/core/config.h               |   4 +-
 src/entities/Entity.cpp         |   4 +-
 src/objects/ParticleObject.cpp  | 109 ++++++-
 src/peds/Ped.cpp                |  10 +-
 src/peds/PlayerPed.cpp          |   6 +-
 src/render/Fluff.cpp            |  42 ++-
 src/save/GenericGameStorage.cpp | 519 ++++++++++++++++++++++++++++++++
 src/save/GenericGameStorage.h   |   5 +
 src/save/PCSave.cpp             |   7 +
 src/save/PCSave.h               |   2 +-
 src/save/SaveBuf.h              |   8 +
 src/skel/crossplatform.cpp      |  23 ++
 src/skel/crossplatform.h        |   3 +
 src/vehicles/Automobile.cpp     |   2 +-
 src/vehicles/Bike.cpp           |   2 +-
 src/vehicles/Boat.cpp           |   2 +-
 src/vehicles/Cranes.cpp         |  84 +++++-
 src/vehicles/Vehicle.cpp        |  99 +++---
 src/vehicles/Vehicle.h          |   2 +-
 src/weapons/Weapon.cpp          |   2 +-
 28 files changed, 1118 insertions(+), 166 deletions(-)

diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp
index db72548f..d7c17a68 100644
--- a/src/control/AutoPilot.cpp
+++ b/src/control/AutoPilot.cpp
@@ -50,45 +50,45 @@ void CAutoPilot::RemoveOnePathNode()
 #ifdef COMPATIBLE_SAVES
 void CAutoPilot::Save(uint8*& buf)
 {
-	WriteSaveBuf<int32>(buf, m_nCurrentRouteNode);
-	WriteSaveBuf<int32>(buf, m_nNextRouteNode);
-	WriteSaveBuf<int32>(buf, m_nPrevRouteNode);
-	WriteSaveBuf<int32>(buf, m_nTimeEnteredCurve);
-	WriteSaveBuf<int32>(buf, m_nTimeToSpendOnCurrentCurve);
-	WriteSaveBuf<uint32>(buf, m_nCurrentPathNodeInfo);
-	WriteSaveBuf<uint32>(buf, m_nNextPathNodeInfo);
-	WriteSaveBuf<uint32>(buf, m_nPreviousPathNodeInfo);
-	WriteSaveBuf<uint32>(buf, m_nAntiReverseTimer);
-	WriteSaveBuf<uint32>(buf, m_nTimeToStartMission);
-	WriteSaveBuf<int8>(buf, m_nPreviousDirection);
-	WriteSaveBuf<int8>(buf, m_nCurrentDirection);
-	WriteSaveBuf<int8>(buf, m_nNextDirection);
-	WriteSaveBuf<int8>(buf, m_nCurrentLane);
-	WriteSaveBuf<int8>(buf, m_nNextLane);
-	WriteSaveBuf<uint8>(buf, m_nDrivingStyle);
-	WriteSaveBuf<uint8>(buf, m_nCarMission);
-	WriteSaveBuf<uint8>(buf, m_nTempAction);
-	WriteSaveBuf<uint32>(buf, m_nTimeTempAction);
-	WriteSaveBuf<float>(buf, m_fMaxTrafficSpeed);
-	WriteSaveBuf<uint8>(buf, m_nCruiseSpeed);
-	WriteSaveBuf<uint8>(buf, m_nCruiseSpeedMultiplierType);
-	SkipSaveBuf(buf, 2);
-	WriteSaveBuf<float>(buf, m_fCruiseSpeedMultiplier);
+	WriteSaveBuf(buf, m_nCurrentRouteNode);
+	WriteSaveBuf(buf, m_nNextRouteNode);
+	WriteSaveBuf(buf, m_nPrevRouteNode);
+	WriteSaveBuf(buf, m_nTimeEnteredCurve);
+	WriteSaveBuf(buf, m_nTimeToSpendOnCurrentCurve);
+	WriteSaveBuf(buf, m_nCurrentPathNodeInfo);
+	WriteSaveBuf(buf, m_nNextPathNodeInfo);
+	WriteSaveBuf(buf, m_nPreviousPathNodeInfo);
+	WriteSaveBuf(buf, m_nAntiReverseTimer);
+	WriteSaveBuf(buf, m_nTimeToStartMission);
+	WriteSaveBuf(buf, m_nPreviousDirection);
+	WriteSaveBuf(buf, m_nCurrentDirection);
+	WriteSaveBuf(buf, m_nNextDirection);
+	WriteSaveBuf(buf, m_nCurrentLane);
+	WriteSaveBuf(buf, m_nNextLane);
+	WriteSaveBuf(buf, m_nDrivingStyle);
+	WriteSaveBuf(buf, m_nCarMission);
+	WriteSaveBuf(buf, m_nTempAction);
+	WriteSaveBuf(buf, m_nTimeTempAction);
+	WriteSaveBuf(buf, m_fMaxTrafficSpeed);
+	WriteSaveBuf(buf, m_nCruiseSpeed);
+	WriteSaveBuf(buf, m_nCruiseSpeedMultiplierType);
+	ZeroSaveBuf(buf, 2);
+	WriteSaveBuf(buf, m_fCruiseSpeedMultiplier);
 	uint8 flags = 0;
 	if (m_bSlowedDownBecauseOfCars) flags |= BIT(0);
 	if (m_bSlowedDownBecauseOfPeds) flags |= BIT(1);
 	if (m_bStayInCurrentLevel) flags |= BIT(2);
 	if (m_bStayInFastLane) flags |= BIT(3);
 	if (m_bIgnorePathfinding) flags |= BIT(4);
-	WriteSaveBuf<uint8>(buf, flags);
-	WriteSaveBuf<uint8>(buf, m_nSwitchDistance);
-	SkipSaveBuf(buf, 2);
-	WriteSaveBuf<float>(buf, m_vecDestinationCoors.x);
-	WriteSaveBuf<float>(buf, m_vecDestinationCoors.y);
-	WriteSaveBuf<float>(buf, m_vecDestinationCoors.z);
-	SkipSaveBuf(buf, 32);
-	WriteSaveBuf<int16>(buf, m_nPathFindNodesCount);
-	SkipSaveBuf(buf, 6);
+	WriteSaveBuf(buf, flags);
+	WriteSaveBuf(buf, m_nSwitchDistance);
+	ZeroSaveBuf(buf, 2);
+	WriteSaveBuf(buf, m_vecDestinationCoors.x);
+	WriteSaveBuf(buf, m_vecDestinationCoors.y);
+	WriteSaveBuf(buf, m_vecDestinationCoors.z);
+	ZeroSaveBuf(buf, 32);
+	WriteSaveBuf(buf, m_nPathFindNodesCount);
+	ZeroSaveBuf(buf, 6);
 }
 
 void CAutoPilot::Load(uint8*& buf)
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 4c3ceb5c..d7394902 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -26,13 +26,6 @@
 #include "VarConsole.h"
 #include "SaveBuf.h"
 
-#define CRUSHER_GARAGE_X1 (1135.5f)
-#define CRUSHER_GARAGE_Y1 (57.0f)
-#define CRUSHER_GARAGE_Z1 (-1.0f)
-#define CRUSHER_GARAGE_X2 (1149.5f)
-#define CRUSHER_GARAGE_Y2 (63.7f)
-#define CRUSHER_GARAGE_Z2 (3.5f)
-
 #define ROTATED_DOOR_OPEN_SPEED (0.015f)
 #define ROTATED_DOOR_CLOSE_SPEED (0.02f)
 #define DEFAULT_DOOR_OPEN_SPEED (0.035f)
@@ -1844,11 +1837,12 @@ void CStoredCar::StoreCar(CVehicle* pVehicle)
 	m_nRadioStation = pVehicle->m_nRadioStation;
 	m_nVariationA = pVehicle->m_aExtras[0];
 	m_nVariationB = pVehicle->m_aExtras[1];
-	m_bBulletproof = pVehicle->bBulletProof;
-	m_bFireproof = pVehicle->bFireProof;
-	m_bExplosionproof = pVehicle->bExplosionProof;
-	m_bCollisionproof = pVehicle->bCollisionProof;
-	m_bMeleeproof = pVehicle->bMeleeProof;
+	m_nFlags = 0;
+	if (pVehicle->bBulletProof) m_nFlags |= FLAG_BULLETPROOF;
+	if (pVehicle->bFireProof) m_nFlags |= FLAG_FIREPROOF;
+	if (pVehicle->bExplosionProof) m_nFlags |= FLAG_EXPLOSIONPROOF;
+	if (pVehicle->bCollisionProof) m_nFlags |= FLAG_COLLISIONPROOF;
+	if (pVehicle->bMeleeProof) m_nFlags |= FLAG_MELEEPROOF;
 	if (pVehicle->IsCar() || pVehicle->IsBike())
 		m_nCarBombType = ((CAutomobile*)pVehicle)->m_bombType; // NB: cast to CAutomobile is original behaviour
 }
@@ -1897,11 +1891,11 @@ CVehicle* CStoredCar::RestoreCar()
 	}
 	pVehicle->bHasBeenOwnedByPlayer = true;
 	pVehicle->m_nDoorLock = CARLOCK_UNLOCKED;
-	pVehicle->bBulletProof = m_bBulletproof;
-	pVehicle->bFireProof = m_bFireproof;
-	pVehicle->bExplosionProof = m_bExplosionproof;
-	pVehicle->bCollisionProof = m_bCollisionproof;
-	pVehicle->bMeleeProof = m_bMeleeproof;
+	if (m_nFlags & FLAG_BULLETPROOF) pVehicle->bBulletProof = true;
+	if (m_nFlags & FLAG_FIREPROOF) pVehicle->bFireProof = true;
+	if (m_nFlags & FLAG_EXPLOSIONPROOF) pVehicle->bExplosionProof = true;
+	if (m_nFlags & FLAG_COLLISIONPROOF) pVehicle->bCollisionProof = true;
+	if (m_nFlags & FLAG_MELEEPROOF) pVehicle->bMeleeProof = true;
 	return pVehicle;
 }
 
@@ -2280,8 +2274,53 @@ void CGarages::Save(uint8 * buf, uint32 * size)
 			WriteSaveBuf(buf, aCarsInSafeHouses[j][i]);
 		}
 	}
-	for (int i = 0; i < NUM_GARAGES; i++)
+	for (int i = 0; i < NUM_GARAGES; i++) {
+#ifdef COMPATIBLE_SAVES
+		WriteSaveBuf(buf, aGarages[i].m_eGarageType);
+		WriteSaveBuf(buf, aGarages[i].m_eGarageState);
+		WriteSaveBuf(buf, aGarages[i].m_nMaxStoredCars);
+		WriteSaveBuf(buf, aGarages[i].field_2);
+		WriteSaveBuf(buf, aGarages[i].m_bClosingWithoutTargetCar);
+		WriteSaveBuf(buf, aGarages[i].m_bDeactivated);
+		WriteSaveBuf(buf, aGarages[i].m_bResprayHappened);
+		ZeroSaveBuf(buf, 1);
+		WriteSaveBuf(buf, aGarages[i].m_nTargetModelIndex);
+		ZeroSaveBuf(buf, 4 + 4);
+		WriteSaveBuf(buf, aGarages[i].m_bDoor1PoolIndex);
+		WriteSaveBuf(buf, aGarages[i].m_bDoor2PoolIndex);
+		WriteSaveBuf(buf, aGarages[i].m_bDoor1IsDummy);
+		WriteSaveBuf(buf, aGarages[i].m_bDoor2IsDummy);
+		WriteSaveBuf(buf, aGarages[i].m_bRecreateDoorOnNextRefresh);
+		WriteSaveBuf(buf, aGarages[i].m_bRotatedDoor);
+		WriteSaveBuf(buf, aGarages[i].m_bCameraFollowsPlayer);
+		ZeroSaveBuf(buf, 1);
+		WriteSaveBuf(buf, aGarages[i].m_vecCorner1);
+		WriteSaveBuf(buf, aGarages[i].m_fInfZ);
+		WriteSaveBuf(buf, aGarages[i].m_vDir1);
+		WriteSaveBuf(buf, aGarages[i].m_vDir2);
+		WriteSaveBuf(buf, aGarages[i].m_fSupZ);
+		WriteSaveBuf(buf, aGarages[i].m_fDir1Len);
+		WriteSaveBuf(buf, aGarages[i].m_fDir2Len);
+		WriteSaveBuf(buf, aGarages[i].m_fInfX);
+		WriteSaveBuf(buf, aGarages[i].m_fSupX);
+		WriteSaveBuf(buf, aGarages[i].m_fInfY);
+		WriteSaveBuf(buf, aGarages[i].m_fSupY);
+		WriteSaveBuf(buf, aGarages[i].m_fDoorPos);
+		WriteSaveBuf(buf, aGarages[i].m_fDoorHeight);
+		WriteSaveBuf(buf, aGarages[i].m_fDoor1X);
+		WriteSaveBuf(buf, aGarages[i].m_fDoor1Y);
+		WriteSaveBuf(buf, aGarages[i].m_fDoor2X);
+		WriteSaveBuf(buf, aGarages[i].m_fDoor2Y);
+		WriteSaveBuf(buf, aGarages[i].m_fDoor1Z);
+		WriteSaveBuf(buf, aGarages[i].m_fDoor2Z);
+		WriteSaveBuf(buf, aGarages[i].m_nTimeToStartAction);
+		WriteSaveBuf(buf, aGarages[i].m_bCollectedCarsState);
+		ZeroSaveBuf(buf, 3 + 4);
+		ZeroSaveBuf(buf, sizeof(aGarages[i].m_sStoredCar));
+#else
 		WriteSaveBuf(buf, aGarages[i]);
+#endif
+	}
 //VALIDATESAVEBUF(*size);
 }
 
@@ -2290,11 +2329,7 @@ const CStoredCar &CStoredCar::operator=(const CStoredCar & other)
 	m_nModelIndex = other.m_nModelIndex;
 	m_vecPos = other.m_vecPos;
 	m_vecAngle = other.m_vecAngle;
-	m_bBulletproof = other.m_bBulletproof;
-	m_bFireproof = other.m_bFireproof;
-	m_bExplosionproof = other.m_bExplosionproof;
-	m_bCollisionproof = other.m_bCollisionproof;
-	m_bMeleeproof = other.m_bMeleeproof;
+	m_nFlags = other.m_nFlags;
 	m_nPrimaryColor = other.m_nPrimaryColor;
 	m_nSecondaryColor = other.m_nSecondaryColor;
 	m_nRadioStation = other.m_nRadioStation;
@@ -2307,7 +2342,7 @@ const CStoredCar &CStoredCar::operator=(const CStoredCar & other)
 void CGarages::Load(uint8* buf, uint32 size)
 {
 //INITSAVEBUF
-	assert(size = 7876);
+	assert(size == 7876);
 	//assert(size == (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + TOTAL_HIDEOUT_GARAGES * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage)));
 	CloseHideOutGaragesBeforeSave();
 	ReadSaveBuf(&NumGarages, buf);
@@ -2328,7 +2363,51 @@ void CGarages::Load(uint8* buf, uint32 size)
 		}
 	}
 	for (int i = 0; i < NUM_GARAGES; i++) {
+#ifdef COMPATIBLE_SAVES
+		ReadSaveBuf(&aGarages[i].m_eGarageType, buf);
+		ReadSaveBuf(&aGarages[i].m_eGarageState, buf);
+		ReadSaveBuf(&aGarages[i].m_nMaxStoredCars, buf);
+		ReadSaveBuf(&aGarages[i].field_2, buf);
+		ReadSaveBuf(&aGarages[i].m_bClosingWithoutTargetCar, buf);
+		ReadSaveBuf(&aGarages[i].m_bDeactivated, buf);
+		ReadSaveBuf(&aGarages[i].m_bResprayHappened, buf);
+		SkipSaveBuf(buf, 1);
+		ReadSaveBuf(&aGarages[i].m_nTargetModelIndex, buf);
+		SkipSaveBuf(buf, 4 + 4);
+		ReadSaveBuf(&aGarages[i].m_bDoor1PoolIndex, buf);
+		ReadSaveBuf(&aGarages[i].m_bDoor2PoolIndex, buf);
+		ReadSaveBuf(&aGarages[i].m_bDoor1IsDummy, buf);
+		ReadSaveBuf(&aGarages[i].m_bDoor2IsDummy, buf);
+		ReadSaveBuf(&aGarages[i].m_bRecreateDoorOnNextRefresh, buf);
+		ReadSaveBuf(&aGarages[i].m_bRotatedDoor, buf);
+		ReadSaveBuf(&aGarages[i].m_bCameraFollowsPlayer, buf);
+		SkipSaveBuf(buf, 1);
+		ReadSaveBuf(&aGarages[i].m_vecCorner1, buf);
+		ReadSaveBuf(&aGarages[i].m_fInfZ, buf);
+		ReadSaveBuf(&aGarages[i].m_vDir1, buf);
+		ReadSaveBuf(&aGarages[i].m_vDir2, buf);
+		ReadSaveBuf(&aGarages[i].m_fSupZ, buf);
+		ReadSaveBuf(&aGarages[i].m_fDir1Len, buf);
+		ReadSaveBuf(&aGarages[i].m_fDir2Len, buf);
+		ReadSaveBuf(&aGarages[i].m_fInfX, buf);
+		ReadSaveBuf(&aGarages[i].m_fSupX, buf);
+		ReadSaveBuf(&aGarages[i].m_fInfY, buf);
+		ReadSaveBuf(&aGarages[i].m_fSupY, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoorPos, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoorHeight, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoor1X, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoor1Y, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoor2X, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoor2Y, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoor1Z, buf);
+		ReadSaveBuf(&aGarages[i].m_fDoor2Z, buf);
+		ReadSaveBuf(&aGarages[i].m_nTimeToStartAction, buf);
+		ReadSaveBuf(&aGarages[i].m_bCollectedCarsState, buf);
+		SkipSaveBuf(buf, 3 + 4);
+		SkipSaveBuf(buf, sizeof(aGarages[i].m_sStoredCar));
+#else
 		ReadSaveBuf(&aGarages[i], buf);
+#endif
 		aGarages[i].m_pDoor1 = nil;
 		aGarages[i].m_pDoor2 = nil;
 		aGarages[i].m_pTarget = nil;
diff --git a/src/control/Garages.h b/src/control/Garages.h
index 07d5f712..358d404d 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -63,14 +63,17 @@ enum
 
 class CStoredCar
 {
+	enum {
+		FLAG_BULLETPROOF = 0x1,
+		FLAG_FIREPROOF = 0x2,
+		FLAG_EXPLOSIONPROOF = 0x4,
+		FLAG_COLLISIONPROOF = 0x8,
+		FLAG_MELEEPROOF = 0x10,
+	};
 	int32 m_nModelIndex;
 	CVector m_vecPos;
 	CVector m_vecAngle;
-	int32 m_bBulletproof : 1;
-	int32 m_bFireproof : 1;
-	int32 m_bExplosionproof : 1;
-	int32 m_bCollisionproof : 1;
-	int32 m_bMeleeproof : 1;
+	int32 m_nFlags;
 	int8 m_nPrimaryColor;
 	int8 m_nSecondaryColor;
 	int8 m_nRadioStation;
@@ -100,7 +103,7 @@ public:
 	bool m_bClosingWithoutTargetCar;
 	bool m_bDeactivated;
 	bool m_bResprayHappened;
-	int m_nTargetModelIndex;
+	int32 m_nTargetModelIndex;
 	CEntity *m_pDoor1;
 	CEntity *m_pDoor2;
 	uint8 m_bDoor1PoolIndex;
diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp
index a962052f..41f9d766 100644
--- a/src/control/Phones.cpp
+++ b/src/control/Phones.cpp
@@ -18,6 +18,12 @@
 #include "Replay.h"
 #endif
 
+#ifdef COMPATIBLE_SAVES
+#define PHONEINFO_SAVE_SIZE 0xA30
+#else
+#define PHONEINFO_SAVE_SIZE sizeof(CPhoneInfo)
+#endif
+
 CPhoneInfo gPhoneInfo;
 
 bool CPhoneInfo::bDisplayingPhoneMessage;  // is phone picked up
@@ -201,11 +207,24 @@ INITSAVEBUF
 	ReadSaveBuf(&m_nMax, buf);
 	ReadSaveBuf(&m_nScriptPhonesMax, buf);
 	for (int i = 0; i < NUMPHONES; i++) {
+#ifdef COMPATIBLE_SAVES
+		ReadSaveBuf(&m_aPhones[i].m_vecPos, buf);
+		SkipSaveBuf(buf, 6 * 4);
+		ReadSaveBuf(&m_aPhones[i].m_repeatedMessagePickupStart, buf);
+		int32 tmp;
+		ReadSaveBuf(&tmp, buf);
+		// It's saved as building pool index in save file, convert it to true entity
+		m_aPhones[i].m_pEntity = tmp != 0 ? CPools::GetBuildingPool()->GetSlot(tmp - 1) : nil;
+		ReadSaveBuf(&m_aPhones[i].m_nState, buf);
+		ReadSaveBuf(&m_aPhones[i].m_visibleToCam, buf);
+		SkipSaveBuf(buf, 3);
+#else
 		ReadSaveBuf(&m_aPhones[i], buf);
 		// It's saved as building pool index in save file, convert it to true entity
 		if (m_aPhones[i].m_pEntity) {
 			m_aPhones[i].m_pEntity = CPools::GetBuildingPool()->GetSlot((uintptr)m_aPhones[i].m_pEntity - 1);
 		}
+#endif
 	}
 VALIDATESAVEBUF(size)
 }
@@ -299,17 +318,29 @@ CPhoneInfo::Initialise(void)
 void
 CPhoneInfo::Save(uint8 *buf, uint32 *size)
 {
-	*size = sizeof(CPhoneInfo);
+	*size = PHONEINFO_SAVE_SIZE;
 INITSAVEBUF
 	WriteSaveBuf(buf, m_nMax);
 	WriteSaveBuf(buf, m_nScriptPhonesMax);
 	for(int phoneId = 0; phoneId < NUMPHONES; phoneId++) {
+#ifdef COMPATIBLE_SAVES
+		WriteSaveBuf(buf, m_aPhones[phoneId].m_vecPos);
+		ZeroSaveBuf(buf, 6 * 4);
+		WriteSaveBuf(buf, m_aPhones[phoneId].m_repeatedMessagePickupStart);
+		// Convert entity pointer to building pool index while saving
+		int32 tmp = m_aPhones[phoneId].m_pEntity ? CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert((CBuilding*)m_aPhones[phoneId].m_pEntity) + 1 : 0;
+		WriteSaveBuf(buf, tmp);
+		WriteSaveBuf(buf, m_aPhones[phoneId].m_nState);
+		WriteSaveBuf(buf, m_aPhones[phoneId].m_visibleToCam);
+		ZeroSaveBuf(buf, 3);
+#else
 		CPhone* phone = WriteSaveBuf(buf, m_aPhones[phoneId]);
 
 		// Convert entity pointer to building pool index while saving
 		if (phone->m_pEntity) {
 			phone->m_pEntity = (CEntity*) (CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert((CBuilding*)phone->m_pEntity) + 1);
 		}
+#endif
 	}
 VALIDATESAVEBUF(*size)
 }
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp
index fd7bfe0e..ab3e0c7c 100644
--- a/src/control/Pickups.cpp
+++ b/src/control/Pickups.cpp
@@ -35,6 +35,12 @@
 #include "Streaming.h"
 #include "SaveBuf.h"
 
+#ifdef COMPATIBLE_SAVES
+#define PICKUPS_SAVE_SIZE 0x4440
+#else
+#define PICKUPS_SAVE_SIZE sizeof(aPickUps)
+#endif
+
 CPickup CPickups::aPickUps[NUMPICKUPS];
 int16 CPickups::NumMessages;
 int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];
@@ -1442,6 +1448,31 @@ CPickups::Load(uint8 *buf, uint32 size)
 INITSAVEBUF
 
 	for (int32 i = 0; i < NUMPICKUPS; i++) {
+#ifdef COMPATIBLE_SAVES
+		ReadSaveBuf(&aPickUps[i].m_vecPos, buf);
+		ReadSaveBuf(&aPickUps[i].m_fRevenue, buf);
+		int32 tmp_pObject;
+		ReadSaveBuf(&tmp_pObject, buf);
+		int32 tmp_pExtraObject;
+		ReadSaveBuf(&tmp_pExtraObject, buf);
+		ReadSaveBuf(&aPickUps[i].m_nQuantity, buf);
+		ReadSaveBuf(&aPickUps[i].m_nTimer, buf);
+		ReadSaveBuf(&aPickUps[i].m_nMoneySpeed, buf);
+		ReadSaveBuf(&aPickUps[i].m_eModelIndex, buf);
+		ReadSaveBuf(&aPickUps[i].m_nIndex, buf);
+		memcpy(aPickUps[i].m_sTextKey, buf, sizeof(aPickUps[i].m_sTextKey));
+		SkipSaveBuf(buf, sizeof(aPickUps[i].m_sTextKey));
+		ReadSaveBuf(&aPickUps[i].m_eType, buf);
+		ReadSaveBuf(&aPickUps[i].m_bRemoved, buf);
+		uint8 flags;
+		ReadSaveBuf(&flags, buf);
+		aPickUps[i].m_bWasAmmoCollected = !!(flags & BIT(0));
+		aPickUps[i].m_bWasControlMessageShown = !!(flags & BIT(1));
+		SkipSaveBuf(buf, 3);
+
+		aPickUps[i].m_pObject = aPickUps[i].m_eType != PICKUP_NONE && tmp_pObject != 0 ? CPools::GetObjectPool()->GetSlot(tmp_pObject - 1) : nil;
+		aPickUps[i].m_pExtraObject = aPickUps[i].m_eType != PICKUP_NONE && tmp_pExtraObject != 0 ? CPools::GetObjectPool()->GetSlot(tmp_pExtraObject - 1) : nil;
+#else
 		ReadSaveBuf(&aPickUps[i], buf);
 
 		if (aPickUps[i].m_eType != PICKUP_NONE) {
@@ -1450,7 +1481,7 @@ INITSAVEBUF
 			if (aPickUps[i].m_pExtraObject != nil)
 				aPickUps[i].m_pExtraObject = CPools::GetObjectPool()->GetSlot((uintptr)aPickUps[i].m_pExtraObject - 1);
 		}
-			
+#endif
 	}
 
 	ReadSaveBuf(&CollectedPickUpIndex, buf);
@@ -1466,12 +1497,34 @@ VALIDATESAVEBUF(size)
 void
 CPickups::Save(uint8 *buf, uint32 *size)
 {
-	*size = sizeof(aPickUps);
+	*size = PICKUPS_SAVE_SIZE;
 	*size += sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected);
 
 INITSAVEBUF
 
 	for (int32 i = 0; i < NUMPICKUPS; i++) {
+#ifdef COMPATIBLE_SAVES
+		WriteSaveBuf(buf, aPickUps[i].m_vecPos);
+		WriteSaveBuf(buf, aPickUps[i].m_fRevenue);
+		int32 tmp = aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil ? CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(aPickUps[i].m_pObject) + 1 : 0;
+		WriteSaveBuf(buf, tmp);
+		tmp = aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pExtraObject != nil ? CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(aPickUps[i].m_pExtraObject) + 1 : 0;
+		WriteSaveBuf(buf, tmp);
+		WriteSaveBuf(buf, aPickUps[i].m_nQuantity);
+		WriteSaveBuf(buf, aPickUps[i].m_nTimer);
+		WriteSaveBuf(buf, aPickUps[i].m_nMoneySpeed);
+		WriteSaveBuf(buf, aPickUps[i].m_eModelIndex);
+		WriteSaveBuf(buf, aPickUps[i].m_nIndex);
+		memcpy(buf, aPickUps[i].m_sTextKey, sizeof(aPickUps[i].m_sTextKey));
+		SkipSaveBuf(buf, sizeof(aPickUps[i].m_sTextKey));
+		WriteSaveBuf(buf, aPickUps[i].m_eType);
+		WriteSaveBuf(buf, aPickUps[i].m_bRemoved);
+		uint8 flags = 0;
+		if (aPickUps[i].m_bWasAmmoCollected) flags |= BIT(0);
+		if (aPickUps[i].m_bWasControlMessageShown) flags |= BIT(1);
+		WriteSaveBuf(buf, flags);
+		ZeroSaveBuf(buf, 3);
+#else
 		CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]);
 		if (buf_pickup->m_eType != PICKUP_NONE) {
 			if (buf_pickup->m_pObject != nil)
@@ -1479,6 +1532,7 @@ INITSAVEBUF
 			if (buf_pickup->m_pExtraObject != nil)
 				buf_pickup->m_pExtraObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(buf_pickup->m_pExtraObject) + 1);
 		}
+#endif
 	}
 
 	WriteSaveBuf(buf, CollectedPickUpIndex);
diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp
index 2806ee30..25b29256 100644
--- a/src/control/Script5.cpp
+++ b/src/control/Script5.cpp
@@ -2267,33 +2267,33 @@ VALIDATESAVEBUF(size)
 void CRunningScript::Save(uint8*& buf)
 {
 #ifdef COMPATIBLE_SAVES
-	SkipSaveBuf(buf, 8);
+	ZeroSaveBuf(buf, 8);
 	for (int i = 0; i < 8; i++)
-		WriteSaveBuf<char>(buf, m_abScriptName[i]);
-	WriteSaveBuf<uint32>(buf, m_nIp);
+		WriteSaveBuf(buf, m_abScriptName[i]);
+	WriteSaveBuf(buf, m_nIp);
 #ifdef CHECK_STRUCT_SIZES
 	static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6");
 #endif
 	for (int i = 0; i < MAX_STACK_DEPTH; i++)
-		WriteSaveBuf<uint32>(buf, m_anStack[i]);
-	WriteSaveBuf<uint16>(buf, m_nStackPointer);
-	SkipSaveBuf(buf, 2);
+		WriteSaveBuf(buf, m_anStack[i]);
+	WriteSaveBuf(buf, m_nStackPointer);
+	ZeroSaveBuf(buf, 2);
 #ifdef CHECK_STRUCT_SIZES
 	static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18");
 #endif
 	for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++)
-		WriteSaveBuf<int32>(buf, m_anLocalVariables[i]);
-	WriteSaveBuf<bool>(buf, m_bIsActive);
-	WriteSaveBuf<bool>(buf, m_bCondResult);
-	WriteSaveBuf<bool>(buf, m_bIsMissionScript);
-	WriteSaveBuf<bool>(buf, m_bSkipWakeTime);
-	WriteSaveBuf<uint32>(buf, m_nWakeTime);
-	WriteSaveBuf<uint16>(buf, m_nAndOrState);
-	WriteSaveBuf<bool>(buf, m_bNotFlag);
-	WriteSaveBuf<bool>(buf, m_bDeatharrestEnabled);
-	WriteSaveBuf<bool>(buf, m_bDeatharrestExecuted);
-	WriteSaveBuf<bool>(buf, m_bMissionFlag);
-	SkipSaveBuf(buf, 2);
+		WriteSaveBuf(buf, m_anLocalVariables[i]);
+	WriteSaveBuf(buf, m_bIsActive);
+	WriteSaveBuf(buf, m_bCondResult);
+	WriteSaveBuf(buf, m_bIsMissionScript);
+	WriteSaveBuf(buf, m_bSkipWakeTime);
+	WriteSaveBuf(buf, m_nWakeTime);
+	WriteSaveBuf(buf, m_nAndOrState);
+	WriteSaveBuf(buf, m_bNotFlag);
+	WriteSaveBuf(buf, m_bDeatharrestEnabled);
+	WriteSaveBuf(buf, m_bDeatharrestExecuted);
+	WriteSaveBuf(buf, m_bMissionFlag);
+	ZeroSaveBuf(buf, 2);
 #else
 	WriteSaveBuf(buf, *this);
 #endif
diff --git a/src/core/Placeable.h b/src/core/Placeable.h
index 9c8c292a..94be3211 100644
--- a/src/core/Placeable.h
+++ b/src/core/Placeable.h
@@ -33,4 +33,4 @@ public:
 	bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2);
 };
 
-VALIDATE_SIZE(CPlaceable, 0x4C);
+VALIDATE_SIZE(CPlaceable, 0x48);
diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp
index d1947813..a85d6846 100644
--- a/src/core/Pools.cpp
+++ b/src/core/Pools.cpp
@@ -310,9 +310,9 @@ INITSAVEBUF
 #else
 			if ((pVehicle->IsCar() || pVehicle->IsBoat() || pVehicle->IsBike()) && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
 #endif
-				WriteSaveBuf<uint32>(buf, pVehicle->m_vehType);
-				WriteSaveBuf<int16>(buf, pVehicle->GetModelIndex());
-				WriteSaveBuf<int32>(buf, GetVehicleRef(pVehicle));
+				WriteSaveBuf(buf, pVehicle->m_vehType);
+				WriteSaveBuf(buf, pVehicle->GetModelIndex());
+				WriteSaveBuf(buf, GetVehicleRef(pVehicle));
 				pVehicle->Save(buf);
 			}
 #else
@@ -321,7 +321,7 @@ INITSAVEBUF
 #else
 			if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
 #endif
-				WriteSaveBuf(buf, (uint32)pVehicle->m_vehType);
+				WriteSaveBuf(buf, pVehicle->m_vehType);
 				WriteSaveBuf(buf, pVehicle->GetModelIndex());
 				WriteSaveBuf(buf, GetVehicleRef(pVehicle));
 				memcpy(buf, pVehicle, sizeof(CAutomobile));
@@ -332,7 +332,7 @@ INITSAVEBUF
 #else
 			if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
 #endif
-				WriteSaveBuf(buf, (uint32)pVehicle->m_vehType);
+				WriteSaveBuf(buf, pVehicle->m_vehType);
 				WriteSaveBuf(buf, pVehicle->GetModelIndex());
 				WriteSaveBuf(buf, GetVehicleRef(pVehicle));
 				memcpy(buf, pVehicle, sizeof(CBoat));
@@ -343,7 +343,7 @@ INITSAVEBUF
 #else
 			if (pVehicle->IsBike() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
 #endif
-				WriteSaveBuf(buf, (uint32)pVehicle->m_vehType);
+				WriteSaveBuf(buf, pVehicle->m_vehType);
 				WriteSaveBuf(buf, pVehicle->GetModelIndex());
 				WriteSaveBuf(buf, GetVehicleRef(pVehicle));
 				memcpy(buf, pVehicle, sizeof(CBike));
diff --git a/src/core/config.h b/src/core/config.h
index ff44eef1..617a1302 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -246,7 +246,8 @@ enum Config {
 
 #define FIX_BUGS		// fixes bugs that we've came across during reversing. You can undefine this only on release builds.
 #define MORE_LANGUAGES		// Add more translations to the game
-#define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible
+#define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible, and keeps saves compatible between platforms
+#define FIX_INCOMPATIBLE_SAVES // try to fix incompatible saves, requires COMPATIBLE_SAVES
 #define LOAD_INI_SETTINGS // as the name suggests. fundamental for CUSTOM_FRONTEND_OPTIONS
 
 #define NO_MOVIES	// add option to disable intro videos
@@ -454,6 +455,7 @@ static_assert(false, "SUPPORT_XBOX_SCRIPT and SUPPORT_MOBILE_SCRIPT are mutually
 #define THIS_IS_STUPID
 #undef MORE_LANGUAGES
 #undef COMPATIBLE_SAVES
+#undef FIX_INCOMPATIBLE_SAVES
 #undef LOAD_INI_SETTINGS
 
 #undef ASPECT_RATIO_SCALE
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 8d51cae7..b2fcfbc7 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -824,7 +824,7 @@ CEntity::SaveEntityFlags(uint8*& buf)
 	if (bStreamingDontDelete) tmp |= BIT(30);
 	if (bRemoveFromWorld) tmp |= BIT(31);
 
-	WriteSaveBuf<uint32>(buf, tmp);
+	WriteSaveBuf(buf, tmp);
 
 	tmp = 0;
 
@@ -845,7 +845,7 @@ CEntity::SaveEntityFlags(uint8*& buf)
 	if (bUnderwater) tmp |= BIT(13);
 	if (bHasPreRenderEffects) tmp |= BIT(14);
 
-	WriteSaveBuf<uint32>(buf, tmp);
+	WriteSaveBuf(buf, tmp);
 }
 
 void
diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp
index d8aa3f60..28c5240f 100644
--- a/src/objects/ParticleObject.cpp
+++ b/src/objects/ParticleObject.cpp
@@ -10,6 +10,12 @@
 #include "DMAudio.h"
 #include "screendroplets.h"
 
+#ifdef COMPATIBLE_SAVES
+#define PARTICLE_OBJECT_SIZEOF 0x84
+#else
+#define PARTICLE_OBJECT_SIZEOF sizeof(CParticleObject)
+#endif
+
 
 CParticleObject gPObjectArray[MAX_PARTICLEOBJECTS];
 
@@ -1051,6 +1057,48 @@ CParticleObject::UpdateFar(void)
 	}
 }
 
+#ifdef COMPATIBLE_SAVES
+static inline void
+SaveOneParticle(CParticleObject *p, uint8 *&buffer)
+{
+#define SkipBuf(buf, num) buf += num
+#define ZeroBuf(buf, num) memset(buf, 0, num); SkipBuf(buf, num)
+#define CopyToBuf(buf, data) memcpy(buf, &data, sizeof(data)); SkipBuf(buf, sizeof(data))
+	// CPlaceable
+	{
+		CopyToBuf(buffer, p->GetMatrix().f);
+		ZeroBuf(buffer, 4);
+		CopyToBuf(buffer, p->GetMatrix().m_hasRwMatrix);
+		ZeroBuf(buffer, 3);
+	}
+
+	// CParticleObject
+	{
+		ZeroBuf(buffer, 4);
+		ZeroBuf(buffer, 4);
+		ZeroBuf(buffer, 4);
+		CopyToBuf(buffer, p->m_nRemoveTimer);
+		CopyToBuf(buffer, p->m_Type);
+		CopyToBuf(buffer, p->m_ParticleType);
+		CopyToBuf(buffer, p->m_nNumEffectCycles);
+		CopyToBuf(buffer, p->m_nSkipFrames);
+		CopyToBuf(buffer, p->m_nFrameCounter);
+		CopyToBuf(buffer, p->m_nState);
+		ZeroBuf(buffer, 2);
+		CopyToBuf(buffer, p->m_vecTarget);
+		CopyToBuf(buffer, p->m_fRandVal);
+		CopyToBuf(buffer, p->m_fSize);
+		CopyToBuf(buffer, p->m_Color);
+		CopyToBuf(buffer, p->m_bRemove);
+		CopyToBuf(buffer, p->m_nCreationChance);
+		ZeroBuf(buffer, 2);
+	}
+#undef SkipBuf
+#undef ZeroBuf
+#undef CopyToBuf
+}
+#endif
+
 bool
 CParticleObject::SaveParticle(uint8 *buffer, uint32 *length)
 {
@@ -1068,27 +1116,35 @@ CParticleObject::SaveParticle(uint8 *buffer, uint32 *length)
 	*(int32 *)buffer = numObjects;
 	buffer += sizeof(int32);
 	
-	int32 objectsLength = sizeof(CParticleObject) * (numObjects + 1);
+	int32 objectsLength = PARTICLE_OBJECT_SIZEOF * (numObjects + 1);
 	int32 dataLength = objectsLength + sizeof(int32);
 	
 	for ( CParticleObject *p = pCloseListHead; p != nil; p = p->m_pNext )
 	{
-#if 0 // todo better
+#ifdef COMPATIBLE_SAVES
+		SaveOneParticle(p, buffer);
+#else
+#ifdef THIS_IS_STUPID
 		*(CParticleObject*)buffer = *p;
 #else
 		memcpy(buffer, p, sizeof(CParticleObject));
 #endif
 		buffer += sizeof(CParticleObject);
+#endif
 	}
 	
 	for ( CParticleObject *p = pFarListHead; p != nil; p = p->m_pNext )
 	{
-#if 0 // todo better
+#ifdef COMPATIBLE_SAVES
+		SaveOneParticle(p, buffer);
+#else
+#ifdef THIS_IS_STUPID
 		*(CParticleObject*)buffer = *p;
 #else
 		memcpy(buffer, p, sizeof(CParticleObject));
 #endif
 		buffer += sizeof(CParticleObject);
+#endif
 	}
 	
 	*length = dataLength;
@@ -1106,7 +1162,7 @@ CParticleObject::LoadParticle(uint8 *buffer, uint32  length)
 	int32 numObjects = *(int32 *)buffer;
 	buffer += sizeof(int32);
 	
-	if ( length != sizeof(CParticleObject) * (numObjects + 1) + sizeof(int32) )
+	if ( length != PARTICLE_OBJECT_SIZEOF * (numObjects + 1) + sizeof(int32) )
 		return false;
 	
 	if ( numObjects == 0 )
@@ -1117,14 +1173,17 @@ CParticleObject::LoadParticle(uint8 *buffer, uint32  length)
 	while ( i < numObjects )
 	{
 		CParticleObject *dst = pUnusedListHead;
+#ifndef COMPATIBLE_SAVES
 		CParticleObject *src = (CParticleObject *)buffer;
 		buffer += sizeof(CParticleObject);
+#endif
 		
 		if ( dst == nil )
 			return false;
 		
 		MoveToList(&pUnusedListHead, &pCloseListHead, dst);
-		
+
+#ifndef COMPATIBLE_SAVES
 		dst->m_nState           = POBJECTSTATE_UPDATE_CLOSE;
 		dst->m_Type             = src->m_Type;
 		dst->m_ParticleType     = src->m_ParticleType;
@@ -1140,6 +1199,46 @@ CParticleObject::LoadParticle(uint8 *buffer, uint32  length)
 		dst->m_nNumEffectCycles = src->m_nNumEffectCycles;
 		dst->m_nSkipFrames      = src->m_nSkipFrames;
 		dst->m_nCreationChance  = src->m_nCreationChance;
+#else
+		dst->m_nState = POBJECTSTATE_UPDATE_CLOSE;
+		dst->m_pParticle = NULL;
+
+#define SkipBuf(buf, num) buf += num
+#define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); SkipBuf(buf, sizeof(data))
+		// CPlaceable
+		{
+			CMatrix matrix;
+			CopyFromBuf(buffer, matrix.f);
+			SkipBuf(buffer, 4);
+			CopyFromBuf(buffer, matrix.m_hasRwMatrix);
+			SkipBuf(buffer, 3);
+			dst->SetPosition(matrix.GetPosition());
+		}
+
+		// CParticleObject
+		{
+			SkipBuf(buffer, 4);
+			SkipBuf(buffer, 4);
+			SkipBuf(buffer, 4);
+			CopyFromBuf(buffer, dst->m_nRemoveTimer);
+			CopyFromBuf(buffer, dst->m_Type);
+			CopyFromBuf(buffer, dst->m_ParticleType);
+			CopyFromBuf(buffer, dst->m_nNumEffectCycles);
+			CopyFromBuf(buffer, dst->m_nSkipFrames);
+			CopyFromBuf(buffer, dst->m_nFrameCounter);
+			SkipBuf(buffer, 2);
+			SkipBuf(buffer, 2);
+			CopyFromBuf(buffer, dst->m_vecTarget);
+			CopyFromBuf(buffer, dst->m_fRandVal);
+			CopyFromBuf(buffer, dst->m_fSize);
+			CopyFromBuf(buffer, dst->m_Color);
+			CopyFromBuf(buffer, dst->m_bRemove);
+			CopyFromBuf(buffer, dst->m_nCreationChance);
+			SkipBuf(buffer, 2);
+		}
+#undef CopyFromBuf
+#undef SkipBuf
+#endif
 		
 		i++;
 	}
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 44712fa0..7fe2520d 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -9585,19 +9585,19 @@ CPed::Say(uint16 audio, int32 time)
 void
 CPed::Save(uint8*& buf)
 {
-	SkipSaveBuf(buf, 52);
+	ZeroSaveBuf(buf, 52);
 	CopyToBuf(buf, GetPosition().x);
 	CopyToBuf(buf, GetPosition().y);
 	CopyToBuf(buf, GetPosition().z);
-	SkipSaveBuf(buf, 288);
+	ZeroSaveBuf(buf, 288);
 	CopyToBuf(buf, CharCreatedBy);
-	SkipSaveBuf(buf, 499);
+	ZeroSaveBuf(buf, 499);
 	CopyToBuf(buf, m_fHealth);
 	CopyToBuf(buf, m_fArmour);
-	SkipSaveBuf(buf, 172);
+	ZeroSaveBuf(buf, 172);
 	for (int i = 0; i < 10; i++) // has to be hardcoded
 		m_weapons[i].Save(buf);
-	SkipSaveBuf(buf, 252);
+	ZeroSaveBuf(buf, 252);
 }
 
 void
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index 9f75b155..8225189f 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -2188,14 +2188,14 @@ void
 CPlayerPed::Save(uint8*& buf)
 {
 	CPed::Save(buf);
-	SkipSaveBuf(buf, 16);
+	ZeroSaveBuf(buf, 16);
 	CopyToBuf(buf, m_fMaxStamina);
-	SkipSaveBuf(buf, 28);
+	ZeroSaveBuf(buf, 28);
 	CopyToBuf(buf, m_nTargettableObjects[0]);
 	CopyToBuf(buf, m_nTargettableObjects[1]);
 	CopyToBuf(buf, m_nTargettableObjects[2]);
 	CopyToBuf(buf, m_nTargettableObjects[3]);
-	SkipSaveBuf(buf, 164);
+	ZeroSaveBuf(buf, 164);
 }
 
 void
diff --git a/src/render/Fluff.cpp b/src/render/Fluff.cpp
index 13dba1a6..1e4d289b 100644
--- a/src/render/Fluff.cpp
+++ b/src/render/Fluff.cpp
@@ -25,6 +25,12 @@
 #include "Coronas.h"
 #include "SaveBuf.h"
 
+#ifdef COMPATIBLE_SAVES
+#define SCRIPTPATHS_SAVE_SIZE 0x9C
+#else
+#define SCRIPTPATHS_SAVE_SIZE sizeof(aArray)
+#endif
+
 CPlaneTrail CPlaneTrails::aArray[6];
 RwImVertexIndex TrailIndices[32] = {
 	0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
@@ -1268,14 +1274,34 @@ INITSAVEBUF
 		aArray[i].Clear();
 
 	for (int32 i = 0; i < 3; i++) {
+#ifdef COMPATIBLE_SAVES
+		ReadSaveBuf(&aArray[i].m_numNodes, buf);
+		SkipSaveBuf(buf, 4);
+		ReadSaveBuf(&aArray[i].m_fTotalLength, buf);
+		ReadSaveBuf(&aArray[i].m_fSpeed, buf);
+		ReadSaveBuf(&aArray[i].m_fPosition, buf);
+		ReadSaveBuf(&aArray[i].m_fObjectLength, buf);
+		ReadSaveBuf(&aArray[i].m_state, buf);
+#else
 		ReadSaveBuf(&aArray[i], buf);
+#endif
 
 		for (int32 j = 0; j < 6; j++) {
+#ifdef COMPATIBLE_SAVES
+			aArray[i].m_pObjects[j] = nil;
+			int32 tmp;
+			ReadSaveBuf(&tmp, buf);
+			if (tmp != 0) {
+				aArray[i].m_pObjects[j] = CPools::GetObjectPool()->GetSlot(tmp - 1);
+				aArray[i].m_pObjects[j]->m_phy_flagA08 = false;
+			}
+#else
 			CScriptPath *pPath = &aArray[i];
 			if (pPath->m_pObjects[j] != nil) {
 				pPath->m_pObjects[j] = CPools::GetObjectPool()->GetSlot((uintptr)pPath->m_pObjects[j] - 1);
 				pPath->m_pObjects[j]->m_phy_flagA08 = false;
 			}
+#endif
 		}
 
 		aArray[i].m_pNode = new CPlaneNode[aArray[i].m_numNodes];
@@ -1287,14 +1313,28 @@ VALIDATESAVEBUF(size)
 }
 
 void CScriptPaths::Save(uint8 *buf, uint32 *size) {
-	*size = sizeof(aArray);
+	*size = SCRIPTPATHS_SAVE_SIZE;
 INITSAVEBUF
 	for (int32 i = 0; i < 3; i++) {
+#ifdef COMPATIBLE_SAVES
+		WriteSaveBuf(buf, aArray[i].m_numNodes);
+		ZeroSaveBuf(buf, 4);
+		WriteSaveBuf(buf, aArray[i].m_fTotalLength);
+		WriteSaveBuf(buf, aArray[i].m_fSpeed);
+		WriteSaveBuf(buf, aArray[i].m_fPosition);
+		WriteSaveBuf(buf, aArray[i].m_fObjectLength);
+		WriteSaveBuf(buf, aArray[i].m_state);
+#else
 		CScriptPath *pPath = WriteSaveBuf(buf, aArray[i]);
+#endif
 
 		for (int32 j = 0; j < 6; j++) {
+#ifdef COMPATIBLE_SAVES
+			WriteSaveBuf(buf, aArray[i].m_pObjects[j] != nil ? CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(aArray[i].m_pObjects[j]) + 1 : 0);
+#else
 			if (pPath->m_pObjects[j] != nil)
 				pPath->m_pObjects[j] = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(pPath->m_pObjects[j]) + 1);
+#endif
 		}
 
 		for (int32 j = 0; j < aArray[i].m_numNodes; j++) {
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index a56ff2c3..12565e3f 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -643,6 +643,525 @@ align4bytes(int32 size)
 	return (size + 3) & 0xFFFFFFFC;
 }
 
+#ifdef FIX_INCOMPATIBLE_SAVES
+#define LoadSaveDataBlockNoCheck(buf, file, size) \
+do { \
+	CFileMgr::Read(file, (const char *)&size, sizeof(size)); \
+	size = align4bytes(size); \
+	CFileMgr::Read(file, (const char *)work_buff, size); \
+	buf = work_buff; \
+} while(0)
+
+#define WriteSavaDataBlockNoFunc(buf, file, size) \
+do { \
+	if (!PcSaveHelper.PcClassSaveRoutine(file, buf, size)) \
+		goto fail; \
+	totalSize += size; \
+} while(0)
+
+#define FixSaveDataBlock(fix_func, file, size) \
+do { \
+	ReadDataFromBufferPointer(buf, size); \
+	memset(work_buff2, 0, sizeof(work_buff2)); \
+	buf2 = work_buff2; \
+	reserved = 0; \
+	MakeSpaceForSizeInBufferPointer(presize, buf2, postsize); \
+	fix_func(save_type, buf, buf2, &size); \
+	CopySizeAndPreparePointer(presize, buf2, postsize, reserved, size); \
+	if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff2, buf2 - work_buff2)) \
+		goto fail; \
+	totalSize += buf2 - work_buff2; \
+} while(0)
+
+#define ReadDataFromBufferPointerWithSize(buf, to, size) memcpy(&to, buf, size); buf += align4bytes(size)
+
+#define ReadBuf(buf, to) memcpy(&to, buf, sizeof(to)); buf += sizeof(to)
+#define WriteBuf(buf, from) memcpy(buf, &from, sizeof(from)); buf += sizeof(from)
+#define CopyBuf(from, to, size) memcpy(to, from, size); to += (size); from += (size)
+#define CopyPtr(from, to) memcpy(to, from, 4); to += 4; from += 8
+#define SkipBuf(buf, size) buf += (size)
+#define SkipBoth(from, to, size) to += (size); from += (size)
+#define SkipPtr(from, to) to += 4; from += 8
+
+// unfortunately we need a 2nd buffer of the same size to store the fixed output ...
+static uint8 work_buff2[sizeof(work_buff)];
+
+enum
+{
+	SAVE_TYPE_NONE = 0,
+	SAVE_TYPE_32_BIT = 1,
+	SAVE_TYPE_64_BIT = 2,
+	SAVE_TYPE_MSVC = 4,
+	SAVE_TYPE_GCC = 8,
+};
+
+uint8
+GetSaveType(char *savename)
+{
+	uint8 save_type = SAVE_TYPE_NONE;
+	int file = CFileMgr::OpenFile(savename, "rb");
+
+	uint32 size;
+	CFileMgr::Read(file, (const char *)&size, sizeof(size));
+
+	uint8 *buf = work_buff;
+	CFileMgr::Read(file, (const char *)work_buff, size); // simple vars + scripts
+
+	LoadSaveDataBlockNoCheck(buf, file, size); // ped pool
+
+	LoadSaveDataBlockNoCheck(buf, file, size); // garages
+	ReadDataFromBufferPointer(buf, size);
+
+	// store for later after we know how much data we need to skip
+	ReadDataFromBufferPointerWithSize(buf, work_buff2, size);
+
+	LoadSaveDataBlockNoCheck(buf, file, size); // game logic
+	LoadSaveDataBlockNoCheck(buf, file, size); // vehicle pool
+	LoadSaveDataBlockNoCheck(buf, file, size); // object pool
+	LoadSaveDataBlockNoCheck(buf, file, size); // paths
+
+	LoadSaveDataBlockNoCheck(buf, file, size); // cranes
+
+	CFileMgr::CloseFile(file);
+
+	ReadDataFromBufferPointer(buf, size);
+
+	if (size == 1000)
+		save_type |= SAVE_TYPE_32_BIT;
+	else if (size == 1160)
+		save_type |= SAVE_TYPE_64_BIT;
+	else
+		assert(0); // this should never happen
+
+	buf = work_buff2;
+
+	buf += 1964; // skip everything before the first garage
+	buf += save_type & SAVE_TYPE_32_BIT ? 28 : 40; // skip first garage up to m_vecCorner1
+
+	CVector2D vecCorner1;
+	float fInfZ, fSupZ;
+
+	ReadBuf(buf, vecCorner1);
+	ReadBuf(buf, fInfZ);
+	SkipBuf(buf, sizeof(CVector2D));
+	SkipBuf(buf, sizeof(CVector2D));
+	ReadBuf(buf, fSupZ);
+
+	// SET_GARAGE -914.129028 -1263.540039 10.706000 -907.137024 -1246.625977 -906.299988 -1266.900024 14.421000
+	if (vecCorner1.x == -914.129028f && vecCorner1.y == -1263.540039f &&
+		fInfZ == 10.706000f && fSupZ == 14.421000f)
+		save_type |= SAVE_TYPE_MSVC;
+	else
+		save_type |= SAVE_TYPE_GCC;
+
+	return save_type;
+}
+
+static void
+FixGarages(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+	// hardcoded: 7876
+	// x86 msvc: 7340
+	// x86 gcc: 7020
+	// amd64 msvc: 7852
+	// amd64 gcc: 7660
+
+	uint8 *buf_start = buf;
+	uint8 *buf2_start = buf2;
+	uint32 read;
+	uint32 written = 7340;
+
+	if (save_type & SAVE_TYPE_32_BIT && save_type & SAVE_TYPE_GCC)
+		read = 7020;
+	else if (save_type & SAVE_TYPE_64_BIT && save_type & SAVE_TYPE_GCC)
+		read = 7660;
+	else
+		read = 7852;
+
+	uint32 ptrsize = save_type & SAVE_TYPE_32_BIT ? 4 : 8;
+
+	CopyBuf(buf, buf2, 4 * 6);
+	CopyBuf(buf, buf2, 4 * TOTAL_COLLECTCARS_GARAGES);
+	CopyBuf(buf, buf2, 4);
+
+	if (save_type & SAVE_TYPE_GCC)
+	{
+		for (int32 i = 0; i < NUM_GARAGE_STORED_CARS; i++)
+		{
+			for (int32 j = 0; j < TOTAL_HIDEOUT_GARAGES; j++)
+			{
+				CopyBuf(buf, buf2, 4 + sizeof(CVector) + sizeof(CVector));
+				uint8 nFlags8;
+				ReadBuf(buf, nFlags8);
+				int32 nFlags32 = nFlags8;
+				WriteBuf(buf2, nFlags32);
+				CopyBuf(buf, buf2, 1 * 6);
+				SkipBuf(buf, 1);
+				SkipBuf(buf2, 2);
+			}
+		}
+	}
+	else
+	{
+		CopyBuf(buf, buf2, sizeof(CStoredCar) * NUM_GARAGE_STORED_CARS * TOTAL_HIDEOUT_GARAGES);
+	}
+
+	for (int32 i = 0; i < NUM_GARAGES; i++)
+	{
+		CopyBuf(buf, buf2, 1 * 7);
+		SkipBoth(buf, buf2, 1);
+		CopyBuf(buf, buf2, 4);
+		SkipBuf(buf, ptrsize - 4); // write 4 bytes padding if 8 byte pointer, if not, write 0
+		SkipBuf(buf, ptrsize * 2);
+		SkipBuf(buf2, 4 * 2);
+		CopyBuf(buf, buf2, 1 * 7);
+		SkipBoth(buf, buf2, 1);
+		CopyBuf(buf, buf2, sizeof(CVector2D) * 3 + 4 * 17 + 1);
+		SkipBoth(buf, buf2, 3);
+		SkipBuf(buf, ptrsize);
+		SkipBuf(buf2, 4);
+
+		if (save_type & SAVE_TYPE_GCC)
+			SkipBuf(buf, save_type & SAVE_TYPE_64_BIT ? 36 + 4 : 36); // sizeof(CStoredCar) on gcc 64/32 before fix
+		else
+			SkipBuf(buf, sizeof(CStoredCar));
+
+		SkipBuf(buf2, sizeof(CStoredCar));
+	}
+}
+
+static void
+FixCranes(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+	uint8 *buf_start = buf;
+	uint8 *buf2_start = buf2;
+	uint32 read = 2 * sizeof(uint32) + 0x480; // sizeof(aCranes)
+	uint32 written = 2 * sizeof(uint32) + 0x3E0; // see CRANES_SAVE_SIZE
+
+	CopyBuf(buf, buf2, 4 + 4);
+
+	for (int32 i = 0; i < NUM_CRANES; i++)
+	{
+		CopyPtr(buf, buf2);
+		CopyPtr(buf, buf2);
+		CopyBuf(buf, buf2, 14 * 4 + sizeof(CVector) * 3 + sizeof(CVector2D));
+		SkipBuf(buf, 4);
+		CopyPtr(buf, buf2);
+		CopyBuf(buf, buf2, 4 + 7 * 1);
+		SkipBuf(buf, 5);
+		SkipBuf(buf2, 1);
+	}
+
+	*size = 0;
+
+	assert(buf - buf_start == read);
+	assert(buf2 - buf2_start == written);
+
+	*size = written;
+}
+
+static void
+FixPickups(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+	uint8 *buf_start = buf;
+	uint8 *buf2_start = buf2;
+	uint32 read = 0x5400 + sizeof(uint16) + sizeof(uint16) + sizeof(int32) * NUMCOLLECTEDPICKUPS; // sizeof(aPickUps)
+	uint32 written = 0x4440 + sizeof(uint16) + sizeof(uint16) + sizeof(int32) * NUMCOLLECTEDPICKUPS; // see PICKUPS_SAVE_SIZE
+
+	for (int32 i = 0; i < NUMPICKUPS; i++)
+	{
+		CopyBuf(buf, buf2, sizeof(CVector) + 4);
+		CopyPtr(buf, buf2);
+		CopyPtr(buf, buf2);
+		CopyBuf(buf, buf2, 4 * 2 + 2 * 3 + 8 + 1 * 3);
+		SkipBuf(buf, 7);
+		SkipBuf(buf2, 3);
+	}
+
+	CopyBuf(buf, buf2, 2);
+	SkipBoth(buf, buf2, 2);
+
+	CopyBuf(buf, buf2, NUMCOLLECTEDPICKUPS * 4);
+
+	*size = 0;
+
+	assert(buf - buf_start == read);
+	assert(buf2 - buf2_start == written);
+
+	*size = written;
+}
+
+static void
+FixPhoneInfo(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+	uint8 *buf_start = buf;
+	uint8 *buf2_start = buf2;
+	uint32 read = 0x1138; // sizeof(CPhoneInfo)
+	uint32 written = 0xA30; // see PHONEINFO_SAVE_SIZE
+
+	CopyBuf(buf, buf2, 4 + 4);
+
+	for (int32 i = 0; i < NUMPHONES; i++)
+	{
+		CopyBuf(buf, buf2, sizeof(CVector));
+		SkipBuf(buf, 4);
+		SkipPtr(buf, buf2);
+		SkipPtr(buf, buf2);
+		SkipPtr(buf, buf2);
+		SkipPtr(buf, buf2);
+		SkipPtr(buf, buf2);
+		SkipPtr(buf, buf2);
+		CopyBuf(buf, buf2, 4);
+		SkipBuf(buf, 4);
+		CopyPtr(buf, buf2);
+		CopyBuf(buf, buf2, 4 + 1);
+		SkipBoth(buf, buf2, 3);
+	}
+
+	*size = 0;
+
+	assert(buf - buf_start == read);
+	assert(buf2 - buf2_start == written);
+
+	*size = written;
+}
+
+static void
+FixParticles(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+	uint8 *buf_start = buf;
+	uint8 *buf2_start = buf2;
+
+	int32 numObjects;
+	ReadBuf(buf, numObjects);
+	WriteBuf(buf2, numObjects);
+
+	uint32 read = 0x98 * (numObjects + 1) + 4; // sizeof(CParticleObject)
+	uint32 written = 0x84 * (numObjects + 1) + 4; // see PARTICLE_OBJECT_SIZEOF
+
+	for (int32 i = 0; i < numObjects; i++)
+	{
+		// CPlaceable
+		CopyBuf(buf, buf2, 4 * 4 * 4);
+		SkipPtr(buf, buf2);
+		CopyBuf(buf, buf2, 1);
+		SkipBuf(buf, 7);
+		SkipBuf(buf2, 3);
+
+		// CParticleObject
+		SkipPtr(buf, buf2);
+		SkipPtr(buf, buf2);
+		SkipPtr(buf, buf2);
+		CopyBuf(buf, buf2, 4 * 3 + 2 * 1 + 2 * 2);
+		SkipBoth(buf, buf2, 2);
+		CopyBuf(buf, buf2, sizeof(CVector) + 2 * 4 + sizeof(CRGBA) + 2 * 1);
+		SkipBoth(buf, buf2, 2);
+	}
+
+	SkipBuf(buf, 0x98); // sizeof(CParticleObject)
+	SkipBuf(buf2, 0x84); // see PARTICLE_OBJECT_SIZEOF
+
+	*size = 0;
+
+	assert(buf - buf_start == read);
+	assert(buf2 - buf2_start == written);
+
+	*size = written;
+}
+
+static void
+FixScriptPaths(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+	uint8 *buf_start = buf;
+	uint8 *buf2_start = buf2;
+	uint32 read = 0x108; // sizeof(CScriptPath) * 3
+	uint32 written = 0x9C; // see SCRIPTPATHS_SAVE_SIZE
+
+	for (int32 i = 0; i < 3; i++)
+	{
+		int32 numNodes;
+		ReadBuf(buf, numNodes);
+		WriteBuf(buf2, numNodes);
+		SkipBuf(buf, 4);
+		SkipPtr(buf, buf2);
+		CopyBuf(buf, buf2, 4 * 5);
+		SkipBuf(buf, 4);
+
+		for (int32 i = 0; i < 6; i++)
+		{
+			CopyPtr(buf, buf2);
+		}
+
+		for (int32 i = 0; i < numNodes; i++)
+		{
+			CopyBuf(buf, buf2, sizeof(CPlaneNode));
+			read += sizeof(CPlaneNode);
+			written += sizeof(CPlaneNode);
+		}
+	}
+
+	*size = 0;
+
+	assert(buf - buf_start == read);
+	assert(buf2 - buf2_start == written);
+
+	*size = written;
+}
+
+bool
+FixSave(int32 slot, uint8 save_type)
+{
+	if (save_type & SAVE_TYPE_32_BIT && save_type & SAVE_TYPE_MSVC)
+		return true;
+
+	bool success = false;
+
+	uint8 *buf, *presize, *postsize, *buf2;
+	uint32 size;
+	uint32 reserved;
+
+	uint32 totalSize;
+
+	char savename[MAX_PATH];
+	char savename_bak[MAX_PATH];
+
+	sprintf(savename, "%s%i%s", DefaultPCSaveFileName, slot + 1, ".b");
+	sprintf(savename_bak, "%s%i%s.%lld.bak", DefaultPCSaveFileName, slot + 1, ".b", time(nil));
+
+	assert(caserename(savename, savename_bak) == 0);
+
+	int file_in = CFileMgr::OpenFile(savename_bak, "rb");
+	int file_out = CFileMgr::OpenFileForWriting(savename);
+
+	CheckSum = 0;
+	totalSize = 0;
+
+	CFileMgr::Read(file_in, (const char *)&size, sizeof(size));
+
+	buf = work_buff;
+	CFileMgr::Read(file_in, (const char *)work_buff, size); // simple vars + scripts
+
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // ped pool
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // garages
+	FixSaveDataBlock(FixGarages, file_out, size); // garages need to be fixed in either case
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // game logic
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // vehicle pool
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // object pool
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // paths
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // cranes
+	if (save_type & SAVE_TYPE_64_BIT)
+		FixSaveDataBlock(FixCranes, file_out, size);
+	else
+		WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // pickups
+	if (save_type & SAVE_TYPE_64_BIT)
+		FixSaveDataBlock(FixPickups, file_out, size);
+	else
+		WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // phoneinfo
+	if (save_type & SAVE_TYPE_64_BIT)
+		FixSaveDataBlock(FixPhoneInfo, file_out, size);
+	else
+		WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // restart
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // radar blips
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // zones
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // gang data
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // car generators
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // particles
+	if (save_type & SAVE_TYPE_64_BIT)
+		FixSaveDataBlock(FixParticles, file_out, size);
+	else
+		WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // audio script objects
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // script paths
+	if (save_type & SAVE_TYPE_64_BIT)
+		FixSaveDataBlock(FixScriptPaths, file_out, size);
+	else
+		WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // player info
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // stats
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // set pieces
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // streaming
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	LoadSaveDataBlockNoCheck(buf, file_in, size); // ped type
+	WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+	memset(work_buff, 0, sizeof(work_buff));
+
+	for (int i = 0; i < 4; i++) {
+		size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4);
+		if (size > sizeof(work_buff))
+			size = sizeof(work_buff);
+		if (size > 4) {
+			if (!PcSaveHelper.PcClassSaveRoutine(file_out, work_buff, size))
+				goto fail;
+			totalSize += size;
+		}
+	}
+
+	if (!CFileMgr::Write(file_out, (const char *)&CheckSum, sizeof(CheckSum)))
+		goto fail;
+
+	success = true;
+
+fail:;
+	CFileMgr::CloseFile(file_in);
+	CFileMgr::CloseFile(file_out);
+
+	return success;
+}
+
+#undef LoadSaveDataBlockNoCheck
+#undef WriteSavaDataBlockNoFunc
+#undef FixSaveDataBlock
+#undef ReadDataFromBufferPointerWithSize
+#undef ReadBuf
+#undef WriteBuf
+#undef CopyBuf
+#undef CopyPtr
+#undef SkipBuf
+#undef SkipBoth
+#undef SkipPtr
+#endif
+
 #ifdef MISSION_REPLAY
 
 void DisplaySaveResult(int unk, char* name)
diff --git a/src/save/GenericGameStorage.h b/src/save/GenericGameStorage.h
index 65f1cc16..b2bf7a24 100644
--- a/src/save/GenericGameStorage.h
+++ b/src/save/GenericGameStorage.h
@@ -25,6 +25,11 @@ bool CheckDataNotCorrupt(int32 slot, char *name);
 bool RestoreForStartLoad();
 int align4bytes(int32 size);
 
+#ifdef FIX_INCOMPATIBLE_SAVES
+uint8 GetSaveType(char *savename);
+bool FixSave(int32 slot, uint8 save_type);
+#endif
+
 extern char DefaultPCSaveFileName[260];
 extern char ValidSaveName[260];
 extern char LoadFileName[256];
diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp
index c9045705..a33e9d90 100644
--- a/src/save/PCSave.cpp
+++ b/src/save/PCSave.cpp
@@ -122,6 +122,13 @@ C_PcSave::PopulateSlotInfo()
 		}
 		if (Slots[i] == SLOT_OK) {
 			if (CheckDataNotCorrupt(i, savename)) {
+#ifdef FIX_INCOMPATIBLE_SAVES
+				if (!FixSave(i, GetSaveType(savename))) {
+					CMessages::InsertNumberInString(TheText.Get("FEC_SLC"), i + 1, -1, -1, -1, -1, -1, SlotFileName[i]);
+					Slots[i] = SLOT_CORRUPTED;
+					continue;
+				}
+#endif
 				SYSTEMTIME st;
 				memcpy(&st, &header.SaveDateTime, sizeof(SYSTEMTIME));
 				const char *month;
diff --git a/src/save/PCSave.h b/src/save/PCSave.h
index 2e85867a..2a29fa95 100644
--- a/src/save/PCSave.h
+++ b/src/save/PCSave.h
@@ -33,7 +33,7 @@ public:
 	void PopulateSlotInfo();
 	bool DeleteSlot(int32 slot);
 	int8 SaveSlot(int32 slot);
-	bool PcClassSaveRoutine(int32 a2, uint8 *data, uint32 size);
+	bool PcClassSaveRoutine(int32 file, uint8 *data, uint32 size);
 	static void SetSaveDirectory(const char *path);
 };
 
diff --git a/src/save/SaveBuf.h b/src/save/SaveBuf.h
index 6e9b3ae9..d0817e9a 100644
--- a/src/save/SaveBuf.h
+++ b/src/save/SaveBuf.h
@@ -64,6 +64,14 @@ WriteSaveBuf(uint8 *&buf, uint32 &length, const T &value)
 	return p;
 }
 
+#ifdef COMPATIBLE_SAVES
+inline void
+ZeroSaveBuf(uint8 *&buf, uint32 length)
+{
+	memset(buf, 0, length);
+	SkipSaveBuf(buf, length);
+}
+#endif
 
 #define SAVE_HEADER_SIZE (4*sizeof(char)+sizeof(uint32))
 
diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp
index 68df6704..f7016b21 100644
--- a/src/skel/crossplatform.cpp
+++ b/src/skel/crossplatform.cpp
@@ -155,6 +155,29 @@ FILE* _fcaseopen(char const* filename, char const* mode)
     return result;
 }
 
+int _caserename(const char *old_filename, const char *new_filename)
+{
+    int result;
+    char *real_old = casepath(old_filename);
+    char *real_new = casepath(new_filename);
+
+    // hack so we don't even try to rename it to new_filename if it already exists
+    if (!real_new) {
+        free(real_old);
+        return -1;
+    }
+
+    if (!real_old)
+        result = rename(old_filename, real_new);
+    else
+        result = rename(real_old, real_new);
+
+    free(real_old);
+    free(real_new);
+
+    return result;
+}
+
 // Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
 // Returned string should freed manually (if exists)
 char* casepath(char const* path, bool checkPathFirst)
diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h
index a073f854..f37e64a1 100644
--- a/src/skel/crossplatform.h
+++ b/src/skel/crossplatform.h
@@ -33,6 +33,7 @@ char *_strdate(char *buf);
 #endif
 extern DWORD _dwOperatingSystemVersion;
 #define fcaseopen fopen
+#define caserename rename
 #else
 char *strupr(char *str);
 char *strlwr(char *str);
@@ -55,6 +56,8 @@ extern long _dwOperatingSystemVersion;
 char *casepath(char const *path, bool checkPathFirst = true);
 FILE *_fcaseopen(char const *filename, char const *mode);
 #define fcaseopen _fcaseopen
+int _caserename(const char *old_filename, const char *new_filename);
+#define caserename _caserename
 #endif
 
 #ifdef RW_GL3
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 8a50ddcf..5e2b0c10 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -5871,7 +5871,7 @@ CAutomobile::Save(uint8*& buf)
 {
 	CVehicle::Save(buf);
 	WriteSaveBuf(buf, Damage);
-	SkipSaveBuf(buf, 1500 - 672 - sizeof(CDamageManager));
+	ZeroSaveBuf(buf, 1500 - 672 - sizeof(CDamageManager));
 }
 
 void
diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp
index c42d342e..a65b64d2 100644
--- a/src/vehicles/Bike.cpp
+++ b/src/vehicles/Bike.cpp
@@ -2950,7 +2950,7 @@ void
 CBike::Save(uint8*& buf)
 {
 	CVehicle::Save(buf);
-	SkipSaveBuf(buf, 1260 - 672);
+	ZeroSaveBuf(buf, 1260 - 672);
 }
 
 void
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 85a41099..73957107 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -1477,7 +1477,7 @@ void
 CBoat::Save(uint8*& buf)
 {
 	CVehicle::Save(buf);
-	SkipSaveBuf(buf, 1216 - 672);
+	ZeroSaveBuf(buf, 1216 - 672);
 }
 
 void
diff --git a/src/vehicles/Cranes.cpp b/src/vehicles/Cranes.cpp
index f217f055..934ccb08 100644
--- a/src/vehicles/Cranes.cpp
+++ b/src/vehicles/Cranes.cpp
@@ -37,6 +37,12 @@
 #define MIN_VALID_POSITION (-10000.0f)
 #define DEFAULT_OFFSET (20.0f)
 
+#ifdef COMPATIBLE_SAVES
+#define CRANES_SAVE_SIZE 0x3E0
+#else
+#define CRANES_SAVE_SIZE sizeof(aCranes)
+#endif
+
 uint32 TimerForCamInterpolation;
 
 uint32 CCranes::CarsCollectedMilitaryCrane;
@@ -622,10 +628,45 @@ void CCranes::Save(uint8* buf, uint32* size)
 {
 	INITSAVEBUF
 
-	*size = 2 * sizeof(uint32) + sizeof(aCranes);
+	*size = 2 * sizeof(uint32) + CRANES_SAVE_SIZE;
 	WriteSaveBuf(buf, NumCranes);
 	WriteSaveBuf(buf, CarsCollectedMilitaryCrane);
 	for (int i = 0; i < NUM_CRANES; i++) {
+#ifdef COMPATIBLE_SAVES
+		int32 tmp = aCranes[i].m_pCraneEntity != nil ? CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert(aCranes[i].m_pCraneEntity) + 1 : 0;
+		WriteSaveBuf(buf, tmp);
+		tmp = aCranes[i].m_pHook != nil ? CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(aCranes[i].m_pHook) + 1 : 0;
+		WriteSaveBuf(buf, tmp);
+		WriteSaveBuf(buf, aCranes[i].m_fPickupX1);
+		WriteSaveBuf(buf, aCranes[i].m_fPickupX2);
+		WriteSaveBuf(buf, aCranes[i].m_fPickupY1);
+		WriteSaveBuf(buf, aCranes[i].m_fPickupY2);
+		WriteSaveBuf(buf, aCranes[i].m_vecDropoffTarget);
+		WriteSaveBuf(buf, aCranes[i].m_fDropoffHeading);
+		WriteSaveBuf(buf, aCranes[i].m_fPickupAngle);
+		WriteSaveBuf(buf, aCranes[i].m_fDropoffAngle);
+		WriteSaveBuf(buf, aCranes[i].m_fPickupDistance);
+		WriteSaveBuf(buf, aCranes[i].m_fDropoffDistance);
+		WriteSaveBuf(buf, aCranes[i].m_fPickupHeight);
+		WriteSaveBuf(buf, aCranes[i].m_fDropoffHeight);
+		WriteSaveBuf(buf, aCranes[i].m_fHookAngle);
+		WriteSaveBuf(buf, aCranes[i].m_fHookOffset);
+		WriteSaveBuf(buf, aCranes[i].m_fHookHeight);
+		WriteSaveBuf(buf, aCranes[i].m_vecHookInitPos);
+		WriteSaveBuf(buf, aCranes[i].m_vecHookCurPos);
+		WriteSaveBuf(buf, aCranes[i].m_vecHookVelocity);
+		tmp = aCranes[i].m_pVehiclePickedUp != nil ? CPools::GetVehiclePool()->GetJustIndex_NoFreeAssert(aCranes[i].m_pVehiclePickedUp) + 1 : 0;
+		WriteSaveBuf(buf, tmp);
+		WriteSaveBuf(buf, aCranes[i].m_nTimeForNextCheck);
+		WriteSaveBuf(buf, aCranes[i].m_nCraneStatus);
+		WriteSaveBuf(buf, aCranes[i].m_nCraneState);
+		WriteSaveBuf(buf, aCranes[i].m_nVehiclesCollected);
+		WriteSaveBuf(buf, aCranes[i].m_bIsCrusher);
+		WriteSaveBuf(buf, aCranes[i].m_bIsMilitaryCrane);
+		WriteSaveBuf(buf, aCranes[i].m_bWasMilitaryCrane);
+		WriteSaveBuf(buf, aCranes[i].m_bIsTop);
+		ZeroSaveBuf(buf, 1);
+#else
 		CCrane *pCrane = WriteSaveBuf(buf, aCranes[i]);
 		if (pCrane->m_pCraneEntity != nil)
 			pCrane->m_pCraneEntity = (CBuilding*)(CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert(pCrane->m_pCraneEntity) + 1);
@@ -633,6 +674,7 @@ void CCranes::Save(uint8* buf, uint32* size)
 			pCrane->m_pHook = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(pCrane->m_pHook) + 1);
 		if (pCrane->m_pVehiclePickedUp != nil)
 			pCrane->m_pVehiclePickedUp = (CVehicle*)(CPools::GetVehiclePool()->GetJustIndex_NoFreeAssert(pCrane->m_pVehiclePickedUp) + 1);
+#endif
 	}
 
 	VALIDATESAVEBUF(*size);
@@ -644,8 +686,45 @@ void CCranes::Load(uint8* buf, uint32 size)
 
 	ReadSaveBuf(&NumCranes, buf);
 	ReadSaveBuf(&CarsCollectedMilitaryCrane, buf);
-	for (int i = 0; i < NUM_CRANES; i++)
+	for (int i = 0; i < NUM_CRANES; i++) {
+#ifdef COMPATIBLE_SAVES
+		int32 tmp;
+		ReadSaveBuf(&tmp, buf);
+		aCranes[i].m_pCraneEntity = tmp != 0 ? CPools::GetBuildingPool()->GetSlot(tmp - 1) : nil;
+		ReadSaveBuf(&tmp, buf);
+		aCranes[i].m_pHook = tmp != 0 ? CPools::GetObjectPool()->GetSlot(tmp - 1) : nil;
+		ReadSaveBuf(&aCranes[i].m_fPickupX1, buf);
+		ReadSaveBuf(&aCranes[i].m_fPickupX2, buf);
+		ReadSaveBuf(&aCranes[i].m_fPickupY1, buf);
+		ReadSaveBuf(&aCranes[i].m_fPickupY2, buf);
+		ReadSaveBuf(&aCranes[i].m_vecDropoffTarget, buf);
+		ReadSaveBuf(&aCranes[i].m_fDropoffHeading, buf);
+		ReadSaveBuf(&aCranes[i].m_fPickupAngle, buf);
+		ReadSaveBuf(&aCranes[i].m_fDropoffAngle, buf);
+		ReadSaveBuf(&aCranes[i].m_fPickupDistance, buf);
+		ReadSaveBuf(&aCranes[i].m_fDropoffDistance, buf);
+		ReadSaveBuf(&aCranes[i].m_fPickupHeight, buf);
+		ReadSaveBuf(&aCranes[i].m_fDropoffHeight, buf);
+		ReadSaveBuf(&aCranes[i].m_fHookAngle, buf);
+		ReadSaveBuf(&aCranes[i].m_fHookOffset, buf);
+		ReadSaveBuf(&aCranes[i].m_fHookHeight, buf);
+		ReadSaveBuf(&aCranes[i].m_vecHookInitPos, buf);
+		ReadSaveBuf(&aCranes[i].m_vecHookCurPos, buf);
+		ReadSaveBuf(&aCranes[i].m_vecHookVelocity, buf);
+		ReadSaveBuf(&tmp, buf);
+		aCranes[i].m_pVehiclePickedUp = tmp != 0 ? CPools::GetVehiclePool()->GetSlot(tmp - 1) : nil;
+		ReadSaveBuf(&aCranes[i].m_nTimeForNextCheck, buf);
+		ReadSaveBuf(&aCranes[i].m_nCraneStatus, buf);
+		ReadSaveBuf(&aCranes[i].m_nCraneState, buf);
+		ReadSaveBuf(&aCranes[i].m_nVehiclesCollected, buf);
+		ReadSaveBuf(&aCranes[i].m_bIsCrusher, buf);
+		ReadSaveBuf(&aCranes[i].m_bIsMilitaryCrane, buf);
+		ReadSaveBuf(&aCranes[i].m_bWasMilitaryCrane, buf);
+		ReadSaveBuf(&aCranes[i].m_bIsTop, buf);
+		SkipSaveBuf(buf, 1);
+#else
 		ReadSaveBuf(&aCranes[i], buf);
+	}
 	for (int i = 0; i < NUM_CRANES; i++) {
 		CCrane *pCrane = &aCranes[i];
 		if (pCrane->m_pCraneEntity != nil)
@@ -654,6 +733,7 @@ void CCranes::Load(uint8* buf, uint32 size)
 			pCrane->m_pHook = CPools::GetObjectPool()->GetSlot((uintptr)pCrane->m_pHook - 1);
 		if (pCrane->m_pVehiclePickedUp != nil)
 			pCrane->m_pVehiclePickedUp = CPools::GetVehiclePool()->GetSlot((uintptr)pCrane->m_pVehiclePickedUp - 1);
+#endif
 	}
 
 	VALIDATESAVEBUF(size);
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index a41e0fa0..610e63f3 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -2364,42 +2364,42 @@ DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle)
 void
 CVehicle::Save(uint8*& buf)
 {
-	SkipSaveBuf(buf, 4);
-	WriteSaveBuf<float>(buf, GetRight().x);
-	WriteSaveBuf<float>(buf, GetRight().y);
-	WriteSaveBuf<float>(buf, GetRight().z);
-	SkipSaveBuf(buf, 4);
-	WriteSaveBuf<float>(buf, GetForward().x);
-	WriteSaveBuf<float>(buf, GetForward().y);
-	WriteSaveBuf<float>(buf, GetForward().z);
-	SkipSaveBuf(buf, 4);
-	WriteSaveBuf<float>(buf, GetUp().x);
-	WriteSaveBuf<float>(buf, GetUp().y);
-	WriteSaveBuf<float>(buf, GetUp().z);
-	SkipSaveBuf(buf, 4);
-	WriteSaveBuf<float>(buf, GetPosition().x);
-	WriteSaveBuf<float>(buf, GetPosition().y);
-	WriteSaveBuf<float>(buf, GetPosition().z);
-	SkipSaveBuf(buf, 16);
+	ZeroSaveBuf(buf, 4);
+	WriteSaveBuf(buf, GetRight().x);
+	WriteSaveBuf(buf, GetRight().y);
+	WriteSaveBuf(buf, GetRight().z);
+	ZeroSaveBuf(buf, 4);
+	WriteSaveBuf(buf, GetForward().x);
+	WriteSaveBuf(buf, GetForward().y);
+	WriteSaveBuf(buf, GetForward().z);
+	ZeroSaveBuf(buf, 4);
+	WriteSaveBuf(buf, GetUp().x);
+	WriteSaveBuf(buf, GetUp().y);
+	WriteSaveBuf(buf, GetUp().z);
+	ZeroSaveBuf(buf, 4);
+	WriteSaveBuf(buf, GetPosition().x);
+	WriteSaveBuf(buf, GetPosition().y);
+	WriteSaveBuf(buf, GetPosition().z);
+	ZeroSaveBuf(buf, 16);
 	SaveEntityFlags(buf);
-	SkipSaveBuf(buf, 208);
+	ZeroSaveBuf(buf, 208);
 	AutoPilot.Save(buf);
-	WriteSaveBuf<int8>(buf, m_currentColour1);
-	WriteSaveBuf<int8>(buf, m_currentColour2);
-	SkipSaveBuf(buf, 2);
-	WriteSaveBuf<int16>(buf, m_nAlarmState);
-	SkipSaveBuf(buf, 42);
-	WriteSaveBuf<uint8>(buf, m_nNumMaxPassengers);
-	SkipSaveBuf(buf, 3);
-	WriteSaveBuf<float>(buf, field_1D0[0]);
-	WriteSaveBuf<float>(buf, field_1D0[1]);
-	WriteSaveBuf<float>(buf, field_1D0[2]);
-	WriteSaveBuf<float>(buf, field_1D0[3]);
-	SkipSaveBuf(buf, 8);
-	WriteSaveBuf<float>(buf, m_fSteerAngle);
-	WriteSaveBuf<float>(buf, m_fGasPedal);
-	WriteSaveBuf<float>(buf, m_fBrakePedal);
-	WriteSaveBuf<uint8>(buf, VehicleCreatedBy);
+	WriteSaveBuf(buf, m_currentColour1);
+	WriteSaveBuf(buf, m_currentColour2);
+	ZeroSaveBuf(buf, 2);
+	WriteSaveBuf(buf, m_nAlarmState);
+	ZeroSaveBuf(buf, 42);
+	WriteSaveBuf(buf, m_nNumMaxPassengers);
+	ZeroSaveBuf(buf, 3);
+	WriteSaveBuf(buf, field_1D0[0]);
+	WriteSaveBuf(buf, field_1D0[1]);
+	WriteSaveBuf(buf, field_1D0[2]);
+	WriteSaveBuf(buf, field_1D0[3]);
+	ZeroSaveBuf(buf, 8);
+	WriteSaveBuf(buf, m_fSteerAngle);
+	WriteSaveBuf(buf, m_fGasPedal);
+	WriteSaveBuf(buf, m_fBrakePedal);
+	WriteSaveBuf(buf, VehicleCreatedBy);
 	uint8 flags = 0;
 	if (bIsLawEnforcer) flags |= BIT(0);
 	if (bIsLocked) flags |= BIT(3);
@@ -2407,19 +2407,19 @@ CVehicle::Save(uint8*& buf)
 	if (bIsHandbrakeOn) flags |= BIT(5);
 	if (bLightsOn) flags |= BIT(6);
 	if (bFreebies) flags |= BIT(7);
-	WriteSaveBuf<uint8>(buf, flags);
-	SkipSaveBuf(buf, 10);
-	WriteSaveBuf<float>(buf, m_fHealth);
-	WriteSaveBuf<uint8>(buf, m_nCurrentGear);
-	SkipSaveBuf(buf, 3);
-	WriteSaveBuf<float>(buf, m_fChangeGearTime);
-	SkipSaveBuf(buf, 12);
-	WriteSaveBuf<uint32>(buf, m_nTimeOfDeath);
-	SkipSaveBuf(buf, 2);
-	WriteSaveBuf<int16>(buf, m_nBombTimer);
-	SkipSaveBuf(buf, 12);
-	WriteSaveBuf<int8>(buf, m_nDoorLock);
-	SkipSaveBuf(buf, 111);
+	WriteSaveBuf(buf, flags);
+	ZeroSaveBuf(buf, 10);
+	WriteSaveBuf(buf, m_fHealth);
+	WriteSaveBuf(buf, m_nCurrentGear);
+	ZeroSaveBuf(buf, 3);
+	WriteSaveBuf(buf, m_fChangeGearTime);
+	ZeroSaveBuf(buf, 12);
+	WriteSaveBuf(buf, m_nTimeOfDeath);
+	ZeroSaveBuf(buf, 2);
+	WriteSaveBuf(buf, m_nBombTimer);
+	ZeroSaveBuf(buf, 12);
+	WriteSaveBuf(buf, m_nDoorLock);
+	ZeroSaveBuf(buf, 108);
 }
 
 void
@@ -2481,9 +2481,8 @@ CVehicle::Load(uint8*& buf)
 	SkipSaveBuf(buf, 2);
 	ReadSaveBuf(&m_nBombTimer, buf);
 	SkipSaveBuf(buf, 12);
-	ReadSaveBuf(&flags, buf);
-	m_nDoorLock = (eCarLock)flags;
-	SkipSaveBuf(buf, 111);
+	ReadSaveBuf(&m_nDoorLock, buf);
+	SkipSaveBuf(buf, 108);
 }
 #endif
 
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 37b57944..31b52138 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -276,7 +276,7 @@ public:
 	int8 m_comedyControlState;
 	CStoredCollPoly m_aCollPolys[2];     // poly which is under front/rear part of car
 	float m_fSteerInput;
-	uint8 m_vehType;
+	eVehicleType m_vehType;
 
 	static void *operator new(size_t) throw();
 	static void *operator new(size_t sz, int slot) throw();
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 46ca4cc8..36303c2c 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -3285,7 +3285,7 @@ CWeapon::Save(uint8*& buf)
 	CopyToBuf(buf, m_nAmmoTotal);
 	CopyToBuf(buf, m_nTimer);
 	CopyToBuf(buf, m_bAddRotOffset);
-	SkipSaveBuf(buf, 3);
+	ZeroSaveBuf(buf, 3);
 }
 
 void

From 9f0a96ac896cec2e8d094738e23566652ac45f52 Mon Sep 17 00:00:00 2001
From: erorcun <erorcunerorcun@hotmail.com.tr>
Date: Sat, 10 Jul 2021 23:24:27 +0300
Subject: [PATCH 3/8] Physical: division by zero fix

---
 src/entities/Physical.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index 890e7876..e9ae3065 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -521,6 +521,10 @@ CPhysical::ApplySpringDampening(float damping, CVector &springDir, CVector &poin
 {
 	float speedA = DotProduct(speed, springDir);
 	float speedB = DotProduct(GetSpeed(point), springDir);
+#ifdef FIX_BUGS
+	if (speedB == 0.0f)
+		return true;
+#endif
 	float step = Min(CTimer::GetTimeStep(), 3.0f);
 	float impulse = -damping * (speedA + speedB)/2.0f * m_fMass * step * 0.53f;
 	if(bIsHeavy)

From 8a114514d9ea61815c2d391bc5edaa69d1648bfe Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Sun, 11 Jul 2021 00:30:26 +0200
Subject: [PATCH 4/8] fix hotring flap stat line

---
 src/core/Stats.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp
index 7ada0da9..8c6137f2 100644
--- a/src/core/Stats.cpp
+++ b/src/core/Stats.cpp
@@ -1229,7 +1229,11 @@ CStats::ConstructStatLine(int rowIdx)
 	FASTEST_TIME(20, "STFT_21");
 
 	if (FastestTimes[21])
+#ifdef FIX_BUGS
+		STAT_LINE_1(float, "STFT_22", Floor(FastestTimes[21] / 10) / 100, 1);
+#else
 		STAT_LINE_1(float, "STFT_22", FastestTimes[21] / 1000, 1);
+#endif
 
 	if (TopShootingRangeScore > 0.0f)
 		STAT_LINE_1(int, "TOP_SHO", TopShootingRangeScore, 0);

From 58de524d70beff5d917bc9eaf72a0f8d3e18840d Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Sun, 11 Jul 2021 03:26:59 +0200
Subject: [PATCH 5/8] tiny diff fix

---
 src/audio/oal/stream.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp
index 7fc36acd..3789573e 100644
--- a/src/audio/oal/stream.cpp
+++ b/src/audio/oal/stream.cpp
@@ -1648,7 +1648,7 @@ void CStream::SetPlay(bool state)
 	{
 		ALint sourceState = AL_STOPPED;
 		alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState);
-		if (sourceState != AL_STOPPED )
+		if (sourceState != AL_STOPPED)
 			alSourceStop(m_pAlSources[0]);
 
 		sourceState = AL_STOPPED;

From f6860657692ded8e7dd3c569f1cf736f844c75c8 Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Sun, 11 Jul 2021 03:59:37 +0200
Subject: [PATCH 6/8] get rid of // done comments in audiomanager.h

---
 src/audio/AudioManager.h | 332 +++++++++++++++++++--------------------
 1 file changed, 166 insertions(+), 166 deletions(-)

diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
index 2e3aeb6d..bba4b0d7 100644
--- a/src/audio/AudioManager.h
+++ b/src/audio/AudioManager.h
@@ -96,8 +96,8 @@ public:
 			m_nCommentsInBank[i] = 0;
 		m_nActiveBank = 0;
 	}
-	void Add(tPedComment *com); // done
-	void Process();             // done
+	void Add(tPedComment *com);
+	void Process();
 };
 
 VALIDATE_SIZE(cPedComments, 0x490);
@@ -251,34 +251,34 @@ public:
 	~cAudioManager();
 
 	// getters
-	uint32 GetFrameCounter() const { return m_FrameCounter; } // done
-	float GetReflectionsDistance(int32 idx) const { return m_afReflectionsDistances[idx]; } // done
+	uint32 GetFrameCounter() const { return m_FrameCounter; }
+	float GetReflectionsDistance(int32 idx) const { return m_afReflectionsDistances[idx]; }
 	int32 GetRandomNumber(int32 idx) const { return m_anRandomTable[idx]; }
 	int32 GetRandomNumberInRange(int32 idx, int32 low, int32 high) const { return (m_anRandomTable[idx] % (high - low + 1)) + low; }
 	bool8 IsMissionAudioSamplePlaying(uint8 slot) const; // { return m_sMissionAudio.m_nPlayStatus == 1; }
 	bool8 ShouldDuckMissionAudio(uint8 slot) const;
 
 	// "Should" be in alphabetic order, except "getXTalkSfx"
-	void AddDetailsToRequestedOrderList(uint8 sample);                                                                    // done (inlined in vc)
-	void AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 bank, uint8 counter, bool8 notLooping); // done
-	void AddReflectionsToRequestedQueue();                                                                                // done
-	void AddReleasingSounds();                                                                                            // done
-	void AddSampleToRequestedQueue();                                                                                     // done
-	void AgeCrimes();                                                                                                     // done (inlined in vc)
+	void AddDetailsToRequestedOrderList(uint8 sample); // inlined in vc
+	void AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 bank, uint8 counter, bool8 notLooping);
+	void AddReflectionsToRequestedQueue();
+	void AddReleasingSounds();
+	void AddSampleToRequestedQueue();
+	void AgeCrimes(); // inlined in vc
 
-	void CalculateDistance(bool8 &condition, float dist);                                                                   // done
-	bool8 CheckForAnAudioFileOnCD() const;                                                                                  // done
-	void ClearActiveSamples();                                                                                             // done
-	void ClearMissionAudio(uint8 slot);                                                                                    // done (inlined in vc)
-	void ClearRequestedQueue();                                                                                            // done (inlined in vc)
-	uint32 ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2, float speedMultiplier) const; // done
-	int32 ComputePan(float, CVector *);                                                                                    // done
-	uint8 ComputeVolume(uint8 emittingVolume, float soundIntensity, float distance) const;                                 // done
-	int32 CreateEntity(eAudioType type, void *entity);                                                                     // done
+	void CalculateDistance(bool8 &condition, float dist);
+	bool8 CheckForAnAudioFileOnCD() const;
+	void ClearActiveSamples();
+	void ClearMissionAudio(uint8 slot); // inlined in vc
+	void ClearRequestedQueue(); // inlined in vc
+	uint32 ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2, float speedMultiplier) const;
+	int32 ComputePan(float, CVector *);
+	uint8 ComputeVolume(uint8 emittingVolume, float soundIntensity, float distance) const;
+	int32 CreateEntity(eAudioType type, void *entity);
 
-	void DestroyAllGameCreatedEntities();                                                                                  // done
-	void DestroyEntity(int32 id);                                                                                          // done (inlined in vc)
-	void DoPoliceRadioCrackle();                                                                                           // done
+	void DestroyAllGameCreatedEntities();
+	void DestroyEntity(int32 id); // inlined in vc
+	void DoPoliceRadioCrackle();
 
 	// functions returning talk sfx,
 	// order from GetPedCommentSfx
@@ -295,8 +295,8 @@ public:
 	uint32 GetHMYSTTalkSfx(CPed *ped, int16 sound);
 	uint32 GetHMOSTTalkSfx(CPed *ped, int16 sound);
 	uint32 GetHFYRITalkSfx(CPed *ped, int16 sound);
-	uint32 GetHFORITalkSfx(CPed *ped, int16 sound); 
-	uint32 GetHMYRITalkSfx(CPed *ped, int16 sound); 
+	uint32 GetHFORITalkSfx(CPed *ped, int16 sound);
+	uint32 GetHMYRITalkSfx(CPed *ped, int16 sound);
 	uint32 GetHMORITalkSfx(CPed *ped, int16 sound);
 	uint32 GetHFYBETalkSfx(CPed *ped, int16 sound);
 	uint32 GetHFOBETalkSfx(CPed *ped, int16 sound);
@@ -379,170 +379,170 @@ public:
 	uint32 GetGenericFemaleTalkSfx(CPed *ped, int16 sound); // todo names (inlined in vc)
 	// end of functions returning talk sfx
 
-	void GenerateIntegerRandomNumberTable();                                                   // done
-	char *Get3DProviderName(uint8 id) const;                                                   // done
-	char GetCDAudioDriveLetter() const;                                                       // done
-	int8 GetCurrent3DProviderIndex() const;                                                    // done
-	int8 AutoDetect3DProviders() const;                                                        // done
-	float GetCollisionLoopingRatio(uint32 a, uint32 b, float c) const;                         // not used
-	float GetCollisionOneShotRatio(int32 a, float b) const;                                    // done
-	float GetCollisionRatio(float a, float b, float c, float d) const;                         // done (inlined in vc)
-	float GetDistanceSquared(const CVector &v) const;                                          // done (inlined in vc)
-	int32 GetJumboTaxiFreq() const;                                                            // done (inlined in vc)
-	uint8 GetMissionAudioLoadingStatus(uint8 slot) const;                                      // done
-	int8 GetMissionScriptPoliceAudioPlayingStatus() const;                                     // done
-	uint8 GetNum3DProvidersAvailable() const;                                                  // done
-	uint32 GetPedCommentSfx(CPed *ped, int32 sound);                                           // done
-	void GetPhrase(uint32 &phrase, uint32 &prevPhrase, uint32 sample, uint32 maxOffset) const; // done
+	void GenerateIntegerRandomNumberTable();
+	char *Get3DProviderName(uint8 id) const;
+	char GetCDAudioDriveLetter() const;
+	int8 GetCurrent3DProviderIndex() const;
+	int8 AutoDetect3DProviders() const;
+	float GetCollisionLoopingRatio(uint32 a, uint32 b, float c) const; // not used
+	float GetCollisionOneShotRatio(int32 a, float b) const;
+	float GetCollisionRatio(float a, float b, float c, float d) const; // inlined in vc
+	float GetDistanceSquared(const CVector &v) const; // inlined in vc
+	int32 GetJumboTaxiFreq() const; // inlined in vc
+	uint8 GetMissionAudioLoadingStatus(uint8 slot) const;
+	int8 GetMissionScriptPoliceAudioPlayingStatus() const;
+	uint8 GetNum3DProvidersAvailable() const;
+	uint32 GetPedCommentSfx(CPed *ped, int32 sound);
+	void GetPhrase(uint32 &phrase, uint32 &prevPhrase, uint32 sample, uint32 maxOffset) const;
 	float GetVehicleDriveWheelSkidValue(CVehicle *veh, tWheelState wheelState, float gasPedalAudio, cTransmission *transmission,
-	                                    float velocityChange);                                                                        // done
-	float GetVehicleNonDriveWheelSkidValue(CVehicle *veh, tWheelState wheelState, cTransmission *transmission, float velocityChange); // done
+	                                    float velocityChange);
+	float GetVehicleNonDriveWheelSkidValue(CVehicle *veh, tWheelState wheelState, cTransmission *transmission, float velocityChange);
 
-	bool8 HasAirBrakes(int32 model) const; // done
+	bool8 HasAirBrakes(int32 model) const;
 
-	void Initialise();                             // done
-	void InitialisePoliceRadio();                  // done
-	void InitialisePoliceRadioZones();             // done
-	void InterrogateAudioEntities();               // done (inlined)
-	bool8 IsAudioInitialised() const;               // done
-	bool8 IsMissionAudioSampleFinished(uint8 slot); // done
-	bool8 IsMP3RadioChannelAvailable() const;       // done
+	void Initialise();
+	void InitialisePoliceRadio();
+	void InitialisePoliceRadioZones();
+	void InterrogateAudioEntities(); // inlined
+	bool8 IsAudioInitialised() const;
+	bool8 IsMissionAudioSampleFinished(uint8 slot);
+	bool8 IsMP3RadioChannelAvailable() const;
 
-	bool8 MissionScriptAudioUsesPoliceChannel(int32 soundMission) const; //done
+	bool8 MissionScriptAudioUsesPoliceChannel(int32 soundMission) const;
 
-	void PlayLoadedMissionAudio(uint8 slot);                // done
-	void PlayOneShot(int32 index, uint16 sound, float vol); // done
-	void PlaySuspectLastSeen(float x, float y, float z);    // done
-	void PlayerJustGotInCar() const;                        // done
-	void PlayerJustLeftCar() const;                         // done
-	void PostInitialiseGameSpecificSetup();                 // done
-	void PostTerminateGameSpecificShutdown();               // done
-	void PreInitialiseGameSpecificSetup() const;            // done
-	void PreloadMissionAudio(uint8 slot, Const char *name); // done
-	void PreTerminateGameSpecificShutdown();                // done
+	void PlayLoadedMissionAudio(uint8 slot);
+	void PlayOneShot(int32 index, uint16 sound, float vol);
+	void PlaySuspectLastSeen(float x, float y, float z);
+	void PlayerJustGotInCar() const;
+	void PlayerJustLeftCar() const;
+	void PostInitialiseGameSpecificSetup();
+	void PostTerminateGameSpecificShutdown();
+	void PreInitialiseGameSpecificSetup() const;
+	void PreloadMissionAudio(uint8 slot, Const char *name);
+	void PreTerminateGameSpecificShutdown();
 	/// processX - main logic of adding new sounds
-	void ProcessActiveQueues();                              // done
-	bool8 ProcessAirBrakes(cVehicleParams& params);           // done
+	void ProcessActiveQueues();
+	bool8 ProcessAirBrakes(cVehicleParams& params);
 	bool8 ProcessBoatEngine(cVehicleParams& params);          
-	bool8 ProcessBoatMovingOverWater(cVehicleParams& params); //done 
+	bool8 ProcessBoatMovingOverWater(cVehicleParams& params);
 #ifdef GTA_BRIDGE
-	void ProcessBridge();         // done(bcs not exists in VC)
-	void ProcessBridgeMotor();    // done(bcs not exists in VC)
-	void ProcessBridgeOneShots(); // done(bcs not exists in VC)
-	void ProcessBridgeWarning();  // done(bcs not exists in VC)
+	void ProcessBridge();
+	void ProcessBridgeMotor();
+	void ProcessBridgeOneShots();
+	void ProcessBridgeWarning();
 #endif
-	bool8 ProcessCarBombTick(cVehicleParams& params);                         // done
-	void ProcessCarHeli(cVehicleParams& params);                             // done
-	void ProcessCesna(cVehicleParams& params);                               // done
-	//void ProcessCrane();                                                   // done(bcs not exists in VC)
-	bool8 ProcessEngineDamage(cVehicleParams& params);                        // done
-	void ProcessEntity(int32 sound);                                         // done
-	void ProcessExplosions(int32 explosion);                                 // done
-	void ProcessFireHydrant();                                               // done
-	void ProcessFires(int32 entity);                                         // done
-	void ProcessFrontEnd();                                                  // done
-	void ProcessGarages();                                                   // done
-	void ProcessJumbo(cVehicleParams& params);                               // done
-	void ProcessJumboAccel(CPlane *plane);                                   // done
-	void ProcessJumboDecel(CPlane *plane);                                   // done
-	void ProcessJumboFlying();                                               // done
-	void ProcessJumboLanding(CPlane *plane);                                 // done
-	void ProcessJumboTakeOff(CPlane *plane);                               	 // done
-	void ProcessJumboTaxi();                                                 // done
-	void ProcessLoopingScriptObject(uint8 sound);                            // done
-	void ProcessMissionAudio();                                              // done
-	void ProcessMissionAudioSlot(uint8 slot);                                // done
-	void ProcessModelHeliVehicle(cVehicleParams& params);                    // done
-	void ProcessModelVehicle(cVehicleParams& params);                        // done
-	void ProcessOneShotScriptObject(uint8 sound);                            // 
-	void ProcessPed(CPhysical *ped);                                         // done
-	void ProcessPedOneShots(cPedParams &params);                             // 
-	void ProcessPhysical(int32 id);                                          // done
-	void ProcessPlane(cVehicleParams& params);                               // done
-	void ProcessPlayerMood();                                                // done
-	void ProcessPlayersVehicleEngine(cVehicleParams& params, CVehicle* veh); // done
-	void ProcessProjectiles();                                               // done
-	void ProcessRainOnVehicle(cVehicleParams& params);                       // done
-	void ProcessReverb() const;                                              // done
-	bool8 ProcessReverseGear(cVehicleParams& params);                         // done
-	void ProcessScriptObject(int32 id);                                      // done
-	void ProcessSpecial();                                                   // done
+	bool8 ProcessCarBombTick(cVehicleParams& params);
+	void ProcessCarHeli(cVehicleParams& params);
+	void ProcessCesna(cVehicleParams& params);
+	//void ProcessCrane();
+	bool8 ProcessEngineDamage(cVehicleParams& params);
+	void ProcessEntity(int32 sound);
+	void ProcessExplosions(int32 explosion);
+	void ProcessFireHydrant();
+	void ProcessFires(int32 entity);
+	void ProcessFrontEnd();
+	void ProcessGarages();
+	void ProcessJumbo(cVehicleParams& params);
+	void ProcessJumboAccel(CPlane *plane);
+	void ProcessJumboDecel(CPlane *plane);
+	void ProcessJumboFlying();
+	void ProcessJumboLanding(CPlane *plane);
+	void ProcessJumboTakeOff(CPlane *plane);
+	void ProcessJumboTaxi();
+	void ProcessLoopingScriptObject(uint8 sound);
+	void ProcessMissionAudio();
+	void ProcessMissionAudioSlot(uint8 slot);
+	void ProcessModelHeliVehicle(cVehicleParams& params);
+	void ProcessModelVehicle(cVehicleParams& params);
+	void ProcessOneShotScriptObject(uint8 sound);
+	void ProcessPed(CPhysical *ped);
+	void ProcessPedOneShots(cPedParams &params);
+	void ProcessPhysical(int32 id);
+	void ProcessPlane(cVehicleParams& params);
+	void ProcessPlayerMood();
+	void ProcessPlayersVehicleEngine(cVehicleParams& params, CVehicle* veh);
+	void ProcessProjectiles();
+	void ProcessRainOnVehicle(cVehicleParams& params);
+	void ProcessReverb() const;
+	bool8 ProcessReverseGear(cVehicleParams& params);
+	void ProcessScriptObject(int32 id);
+	void ProcessSpecial();
 #ifdef GTA_TRAIN
-	bool8 ProcessTrainNoise(cVehicleParams *params); //done(bcs not exists in VC)
+	bool8 ProcessTrainNoise(cVehicleParams *params);
 #endif
-	void ProcessVehicle(CVehicle *vehicle);                    // done
-	bool8 ProcessVehicleDoors(cVehicleParams &params);          // done
-	void ProcessVehicleEngine(cVehicleParams &params);         // done
-	void ProcessVehicleFlatTyre(cVehicleParams &params);       // done
-	bool8 ProcessVehicleHorn(cVehicleParams &params);           // done
-	void ProcessVehicleOneShots(cVehicleParams &params);       // done
-	bool8 ProcessVehicleReverseWarning(cVehicleParams &params); // done
-	bool8 ProcessVehicleRoadNoise(cVehicleParams &params);      // done
-	bool8 ProcessVehicleSirenOrAlarm(cVehicleParams &params);   // done
-	bool8 ProcessVehicleSkidding(cVehicleParams &params);       // done
-	void ProcessWaterCannon(int32);                            // done
-	void ProcessWeather(int32 id);                             // done
-	bool8 ProcessWetRoadNoise(cVehicleParams& params);          // done
-	void ProcessEscalators();                                  // done
-	void ProcessExtraSounds();                                 // done
+	void ProcessVehicle(CVehicle *vehicle);
+	bool8 ProcessVehicleDoors(cVehicleParams &params);
+	void ProcessVehicleEngine(cVehicleParams &params);
+	void ProcessVehicleFlatTyre(cVehicleParams &params);
+	bool8 ProcessVehicleHorn(cVehicleParams &params);
+	void ProcessVehicleOneShots(cVehicleParams &params);
+	bool8 ProcessVehicleReverseWarning(cVehicleParams &params);
+	bool8 ProcessVehicleRoadNoise(cVehicleParams &params);
+	bool8 ProcessVehicleSirenOrAlarm(cVehicleParams &params);
+	bool8 ProcessVehicleSkidding(cVehicleParams &params);
+	void ProcessWaterCannon(int32);
+	void ProcessWeather(int32 id);
+	bool8 ProcessWetRoadNoise(cVehicleParams& params);
+	void ProcessEscalators();
+	void ProcessExtraSounds();
 
-	int32 RandomDisplacement(uint32 seed) const;                                                                                      // done
-	void ReacquireDigitalHandle() const;                                                                                              // done
-	void ReleaseDigitalHandle() const;                                                                                                // done
-	void ReportCollision(CEntity *entity1, CEntity *entity2, uint8 surface1, uint8 surface2, float collisionPower, float intensity2); // done
-	void ReportCrime(eCrimeType crime, const CVector &pos);                                                                           // done
-	void ResetAudioLogicTimers(uint32 timer);                                                                                         // done
-	void ResetPoliceRadio();                                                                                                          // done
-	void ResetTimers(uint32 time);                                                                                                    // done
+	int32 RandomDisplacement(uint32 seed) const;
+	void ReacquireDigitalHandle() const;
+	void ReleaseDigitalHandle() const;
+	void ReportCollision(CEntity *entity1, CEntity *entity2, uint8 surface1, uint8 surface2, float collisionPower, float intensity2);
+	void ReportCrime(eCrimeType crime, const CVector &pos);
+	void ResetAudioLogicTimers(uint32 timer);
+	void ResetPoliceRadio();
+	void ResetTimers(uint32 time);
 
-	void Service();                                                                             // done
-	void ServiceCollisions();                                                                   // done
-	void ServicePoliceRadio();                                                                  // done
-	void ServicePoliceRadioChannel(uint8 wantedLevel);                                          // done
-	void ServiceSoundEffects();                                                                 // done
-	int8 SetCurrent3DProvider(uint8 which);                                                     // done
-	void SetDynamicAcousticModelingStatus(bool8 status);                                        // done
-	void SetEffectsFadeVol(uint8 volume) const;                                                 // done
-	void SetEffectsMasterVolume(uint8 volume) const;                                            // done
-	void SetMP3BoostVolume(uint8 volume) const;                                                 // done
-	void SetEntityStatus(int32 id, bool8 status);                                               // done
-	uint32 SetLoopingCollisionRequestedSfxFreqAndGetVol(const cAudioCollision &audioCollision); // done
-	void SetMissionAudioLocation(uint8 slot, float x, float y, float z);                        // done
-	void SetMissionScriptPoliceAudio(int32 sfx) const;                                          // inlined and optimized
-	void SetMonoMode(bool8 mono);                                                               // done
-	void SetMusicFadeVol(uint8 volume) const;                                                   // done
-	void SetMusicMasterVolume(uint8 volume) const;                                              // done
-	void SetSpeakerConfig(int32 conf) const;                                                    // done
-	void SetUpLoopingCollisionSound(const cAudioCollision &col, uint8 counter);                 // done
-	void SetUpOneShotCollisionSound(const cAudioCollision &col);                                // done
-	bool8 SetupCrimeReport();                                                                    // done
-	bool8 SetupJumboEngineSound(uint8 vol, uint32 freq);                                         // done
-	bool8 SetupJumboFlySound(uint8 emittingVol);                                                 // done
-	bool8 SetupJumboRumbleSound(uint8 emittingVol);                                              // done
-	bool8 SetupJumboTaxiSound(uint8 vol);                                                        // done
-	bool8 SetupJumboWhineSound(uint8 emittingVol, uint32 freq);                                  // done
-	void SetupPedComments(cPedParams &params, uint16 sound);                                    // done
+	void Service();
+	void ServiceCollisions();
+	void ServicePoliceRadio();
+	void ServicePoliceRadioChannel(uint8 wantedLevel);
+	void ServiceSoundEffects();
+	int8 SetCurrent3DProvider(uint8 which);
+	void SetDynamicAcousticModelingStatus(bool8 status);
+	void SetEffectsFadeVol(uint8 volume) const;
+	void SetEffectsMasterVolume(uint8 volume) const;
+	void SetMP3BoostVolume(uint8 volume) const;
+	void SetEntityStatus(int32 id, bool8 status);
+	uint32 SetLoopingCollisionRequestedSfxFreqAndGetVol(const cAudioCollision &audioCollision);
+	void SetMissionAudioLocation(uint8 slot, float x, float y, float z);
+	void SetMissionScriptPoliceAudio(int32 sfx) const; // inlined and optimized
+	void SetMonoMode(bool8 mono);
+	void SetMusicFadeVol(uint8 volume) const;
+	void SetMusicMasterVolume(uint8 volume) const;
+	void SetSpeakerConfig(int32 conf) const;
+	void SetUpLoopingCollisionSound(const cAudioCollision &col, uint8 counter);
+	void SetUpOneShotCollisionSound(const cAudioCollision &col);
+	bool8 SetupCrimeReport();
+	bool8 SetupJumboEngineSound(uint8 vol, uint32 freq);
+	bool8 SetupJumboFlySound(uint8 emittingVol);
+	bool8 SetupJumboRumbleSound(uint8 emittingVol);
+	bool8 SetupJumboTaxiSound(uint8 vol);
+	bool8 SetupJumboWhineSound(uint8 emittingVol, uint32 freq);
+	void SetupPedComments(cPedParams &params, uint16 sound);
 	void SetupSuspectLastSeenReport();
 
-	void Terminate();                                           // done
-	void TranslateEntity(Const CVector *v1, CVector *v2) const; // done
+	void Terminate();
+	void TranslateEntity(Const CVector *v1, CVector *v2) const;
 
-	void UpdateGasPedalAudio(CVehicle *veh, int vehType);  // done
-	void UpdateReflections();                              // done
-	bool8 UsesReverseWarning(int32 model) const;            // done
-	bool8 UsesSiren(cVehicleParams &params) const;          // done
-	bool8 UsesSirenSwitching(cVehicleParams &params) const; // done
+	void UpdateGasPedalAudio(CVehicle *veh, int vehType);
+	void UpdateReflections();
+	bool8 UsesReverseWarning(int32 model) const;
+	bool8 UsesSiren(cVehicleParams &params) const;
+	bool8 UsesSirenSwitching(cVehicleParams &params) const;
 
-	CVehicle *FindVehicleOfPlayer();                   // done
-	void SetPedTalkingStatus(CPed *ped, bool8 status); // done
-	void SetPlayersMood(uint8 mood, uint32 time);      // done
+	CVehicle *FindVehicleOfPlayer();
+	void SetPedTalkingStatus(CPed *ped, bool8 status);
+	void SetPlayersMood(uint8 mood, uint32 time);
 
 	float Sqrt(float v) const { return v <= 0.0f ? 0.0f : ::Sqrt(v); }
 
 #ifdef GTA_PC
 	// only used in pc
-	void AdjustSamplesVolume();                                                     // done (inlined)
-	uint8 ComputeEmittingVolume(uint8 emittingVolume, float intensity, float dist); // done (inlined)
+	void AdjustSamplesVolume(); // inlined
+	uint8 ComputeEmittingVolume(uint8 emittingVolume, float intensity, float dist); // inlined
 #endif
 };
 

From dc29e7c0441af00393364025ba57330292743544 Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Sun, 11 Jul 2021 23:55:11 +0300
Subject: [PATCH 7/8] Add PED DENSITY and CAR DENSITY lines to GXT

---
 gamefiles/TEXT/american.gxt | Bin 423994 -> 424066 bytes
 gamefiles/TEXT/french.gxt   | Bin 469996 -> 470068 bytes
 gamefiles/TEXT/german.gxt   | Bin 461890 -> 461962 bytes
 gamefiles/TEXT/italian.gxt  | Bin 458946 -> 459018 bytes
 gamefiles/TEXT/spanish.gxt  | Bin 455278 -> 455350 bytes
 utils/gxt/american.txt      |   6 ++++++
 utils/gxt/french.txt        |   6 ++++++
 utils/gxt/german.txt        |   6 ++++++
 utils/gxt/italian.txt       |   6 ++++++
 utils/gxt/spanish.txt       |   6 ++++++
 10 files changed, 30 insertions(+)

diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt
index 4db81fc6e878ff9e43d0c1e18f6fae4364124bd9..39895b0cb4a188a34151cab7f938605a7edbc331 100644
GIT binary patch
delta 1066
zcmZ9~Pe>F|90%~PyE7u$p+k_u2GSvxsKfrTLJEA&KG$hxXNK9?R!wjfk0L5Tdx%yl
z(87b!pOc3UAwor#h9L$99$LIEWT*&&(V>HaL=aKGx9{zxfq~Ea&F}aA{N}A3G~YdJ
zo{5xJw?bgqtm(vnwO!>naImMG0DgQ|P6FPcax1X@JA@AASl6g_`>!(9P8|!&IMo(T
zD^u-<sIc#fwUWH*lIu`Gdq#brf~gzIRIo6pOpDp0WYgkQi~F~vsT7qv(o~9;2jon5
zzsSKOvde;wTn}c*2J@=%rDwvv2xEAzR2_KCk0JV+?0WPK2;K<ioPcHu-YL^+4Qu2a
zotfg(8_E=a@l~02@#>p09iZtjj84;GHU~6KBl|q?Ekw^~NOOn#B^E;^ss=2M`Aan?
zkTPmcVrZb|Rz$`%bTL!x4Sf^Rq7zT1r9~%-Pswh;ZSv-<2Gih%PrYlHlg<V7%id}z
znNHxll%%a_uz2;r*shRG!^#E$7Irk)EZ@VaLs#}{j^jwzRXl;dvo$Ail+ckeS;nMh
zM>@zEnw*~7DIM;0X8UFuURsCOW!iLr5(=&yh!aHfWV5%Ikv|WRU0-w>vm??Xr#K-k
zPC4~ZnmUchbF%MNyK-Vdx|;t{TI3hjb@<HSS@Q8OWTVu@Z8L_GJ7VD34z*}$S6HOQ
zFuX^04NGi7+m{xTdOxMbr0u9jmiuXuGuk38a#qhti=1DHdIYSSR-${8l{V-f1m}n3
zAW!$8Fj8|Im&a>PpmLLJ@t&r|PvQK<#<jr^I(ep_F6!e`ZSNcB)!5^y#f`Q<SL-(K
ym5Y<*V%>7N7<xH)!2?GME%b6Y$ihSby8AG|;Qt?=9NP-f8>UxV9^2B(v;P2ExcRdH

delta 996
zcmXxiPe>F|90%~PyE7u;(ZdP`1rkeiaQ|2!1wO}VcbeImWp>to1*LfKAfm9)9->+5
zV8kAbtdr2CLP)SOuwo+viJ%T0mMAQAMWRCog$N<ResA8Jfq~Ea&F}Z#{C+bx_S#?X
zw$F9=rHu$!p<vhvpu8!a1QxfYQ^3Pt(rKV&Pr4hp_Ai1yW}6qNcK%SBYI~1FMVxA5
zN2RHDI?nAn{H)*ofqloOf_+Oqpn~3u(o`@pCQXMa(`3WcsTOCi3R5Yn*M+GRUvH6f
zLzj8Z%Q>>cyuRWvvUj4;SU!kP-sg6C7@d#(V3B8T0$WRDCr{6S)@AOZ?a@xH&!y?K
zwYTIV^-S^pkJ1#s^i7)HV*IBxHSl>iit~oeEFGvt6|$>)u8FPV3NpH_yFN>x8kY-}
z#FaClQ#j}gokquK=x)?!6l9sf-wkaQVLl0~D$FO*b&u?Lx<#H_P+(}f=F;re9tjsc
z`ee@(_=fGd4kguIDKPb*Va(UbhGrH#4--EWSZr`urwRROgic~fRb@PdwiBV#SW2nL
z87ybeu<MMRqs{3`_p5LQnB^K7v}9D|vxY?t_=q`T!8_O*AR8kij9eKdJ1(CzyeVOx
z(^V1XUH0A<rb(mzfb2TKR6Z;V2l;P=d46nNh08R(Kwkes*8Hq)83}y)&KG&hrV&kU
za`UtVI=9J=X7ZP)?FjQtTmB03P4^E~6m&PkbK=LE1M{5HNnxJzG}R1`4be&T-xP#3
z`Ub71#>HZg{)5<5=p=S$LZ?tIkxhLVEAOI%r|)+5yja=kIXKs}c(YNSZIqi<8|BE8
TvDw;2gzhNa%4%&xeZTM@>@Dy)

diff --git a/gamefiles/TEXT/french.gxt b/gamefiles/TEXT/french.gxt
index 36f4225cc4cb9ee8724d84ad25b43a1f9322c13e..d20206516efc30260144ad07be737181fd6818c1 100644
GIT binary patch
delta 1066
zcmZ9~O=uHA6bJBsn%x*|5fPP$!4D`{#7gtgASIyF?KD}l*<Ci9ekr7apkPnZLLtFa
zM0-&v2qNfB4;6|it+e!_o-9(qgV-KK6HutoLq)|yJ@{sK_TpjTH*epYnfG=#*WwH7
z@tJsiE)xbTm2@)!Z1zYefksw31x#wvX<*Kf?gnNC!{}vZ;Vjk0&P!8m?2<Iqj!jBa
zZQD&@#}a2<p7mU}Oe%;!moG%YD`_g&Sdpf~((7csz^N7&zxbw7v~BpNQq+Eui$fKW
z^LU$VF}JrojPbu=Xw3HFOCg2qh%lmi>fXX;P6Dw5WXq;^)bT;#vgy)Jn}?+7G`o{r
zrk*KopOU6{G%roJ$PP$T1GNhZ`gM~ToZ=J04tJdbHXbO*ag#fBMh8EV3zkIJeBcyT
zUj|O2y%D$@3qKU(nJ(^zj*#kEOyb!t-(nJoku8@S#KvJ2y2dq!W*0l|yX*oVk}B%D
z={goAMYAdj+-n$yL)NuI$#t=HPKCh+hdE8?;b`C_-rowGLgPu`G`5yh6m?eAY1p%G
z$VG7*VCbz1Yk(P!o<r@O3OlbG)Ic54kN!e*Q2R{QM@ATV>pR(U#H7*o$G6B?*%|TT
zqRa99zG>3fdy?!}-c+)ueT)2Grf-oyHV}csG+rXRSIAmD&ka3+j;mr}8zzmYF(E9{
z68JhvwzPt{gi`e_Hl4cdTWngpA3=#bIgvB9>RaTDuK5-@yPFZXY=}+*R>M0yYxE7q
zPwev-gY+LLM*}DEsXcHCE62zMKHN3`Iy{|ey|>(geqOB5k9s%P^P=^dT-&^Fe!J(}
znb6Z4&FXZs8d_{tTdps6+TiHJ5qdaGl%T@}{rk|s;QSw-u4KaWDD<d{l}zN$?|;^P
B^E3be

delta 996
zcmXxiO=uHA6bJBsO*R%0QShT+&>jjRq+pV5D6NRoWlh%I?1ssvpMn*N2zpRZC>Gp`
z#ftPG=pmqoB0a?7L2RK#3Pvbcq(Tl#J&5f=P@xyG3PlgT*_jP2{O0X@GxOeN{!?;u
zE%_iBjO1cq<+A0bftfDl3{X9(oCQu8$~rLOD0cvbz8HF#YoDds#*i}AHZCetZQH0a
z)h<s6b5ESrS_>U`E){%up<alBx-u0^uPD=Dn`>mtHmMfLb!jTa@;7NJh5n0N>_0DZ
z&iy5O%<riTAoVW>gO$Sg)uuR^i!kc@f^bn{JdH*R*(=dI>iDp5#r0{YnIp<{T5~(O
zLOoNwxl@_q^}I6OVymJ|4d@r*IAgiYF)4msn43PgG5t7>yy==eV07?PwO|>1e;GN8
ziPw>Jd|r>-fh#}bC@@Rh4I9uxi%DGCBP}Mec!=!zrbDhC)nFN>!D)7l<I)u$n967f
zEZ65ACDpq%*k;%;;+$+5cG>q)8`9vgz5$aa<PS&A;NIQHSyZ1z)=^v3P_$UlqG1oe
zB^POP`t5zE!RuuXxAM^6YbX^ghZ+b_|0oxt1N{rx8XRQg+7GhF#iX(PM_S~J?@EMm
z(PiqOG))?-?PTtSQ`tHtE%Kkc(jvdDHv!HJvrOK7nQR0F)3MUnxF!}Q$E6WfZwQOD
zG@gu-J;N54Sh^`KHtn2}7MtqT1j;7Qi=56?X_3>iCM|MSHWKhzKb-_j#CC=@=o_R`
z2jrrU{s&8~ku!MI7CDRYV`SSLXqkHxo6J4*yXNQicYi(IbnDLc*yQ$D)57-Hj@z#$
SXLB)n;`C?>v$@3m-~Rz4ChA=P

diff --git a/gamefiles/TEXT/german.gxt b/gamefiles/TEXT/german.gxt
index 671ed18da6b7137f7a2d670349382e260316000c..f96f87d546a6d68b1307163d095487bb8cf72d3f 100644
GIT binary patch
delta 1066
zcmZA0Pe>F|90%~P?#!kr5#&K=r6@aT;r`Ks74n>Y?o7KoGtADms~C1zs*6Ms6uGg7
z0wp>uWsuM%@!-KoGI38u2GSv-Ai<!(qCXdj#X}Sr^n3f>UK)7t`Mvr5-k;yjuHFyb
znhBLdrAkKtER(V9FrXb&jsWq)%2D8HmvRg+`;>cuDI<VEW+zWl?P5ZiYFjhPR9ii(
zOto8=ggr;>HC3*;<k(aYno%#PU~XQS3T`hd(`G%-$ySn6Eqd0ZsT74b(o~A$AIRza
zn8-Qvnd~rsFgpx<3BX`(Z9e`(*sD$Ze@eB$WnLH+XfPa?-qEQWg|oI#D~$$~X}5A4
zIZJn@`O1D}n*V)NS)Ag8GF>2UY8bL?mf}GBsIbR<FNw?7H6*yry%Gy!>!u1=1UvWY
zj-onScMRPx>+Z$Xbqyx7#MyBEo3!Xed0SeXA+|$ye4ZjNXgVx|8y@v;ez$bi2a5Z2
zlq}o#97@{k)RE-13uAhKY#GUn?_<Z*kz%=FP93VI>yF^n#k!-IyHj@z?GJUNEta;Z
z*~Q1?G%Zd~+Y=qmDVFlA1X`DMxTck&3zV?unGD1YHrL43$Ot39e@Ava(P?O#(jsSZ
zTUy*Q|5utijpE)QT+gX><?SJ9k-rd;7Wqy6L3qsI8FC>_HcBQ>Sz(yI2;7uSE$Yk(
zi?lEbBV@-&ibG7FmKKY?z920Y-MAJ+hI<K-^YxLm$oW{27CG)}5I)P(PV{`2Ht08~
zcK?z=j=qBj4ZCVdIr<Lf^tz)ko5)E%oL_noSm|pi&NgC*r^o0+y?dp9xuu|Dm&cd7
zj(r+vn7+|GG1)xPu+luycy9KH3ywGr(BQC<fdwD*mw*8V@BjJ9@s0oujfTE5-Vt2?
F`47kM^9}$2

delta 996
zcmXxiO=uHA6bJBsn{4bsM6d_J6b<%f5%bZ4AJ9&>V>0e$H%vDDvZ9BgJqT8h7FoeU
zMLZNgAc6-eJ>()*8fXqxv{dmRQboZ-K?Ey3h=(GASiv`$*}%f@&AvA??`3a2NUl_q
zv&nF>BL-G33oi{Ur;IbecBgR`xOm7o2cXBe8|brR=x3gDifSkF##Fm1jj6VF-k56V
zuP94joz*wnbm)6j@Ud!MP{CNum<k3KjOnn==Vak<s>S9jZ7N0boi>%?*JpBZ_^is=
z`<3jopuaML2H9q%=KA(`WvQ02^H10eN=&9Pi8yS(MDOU<t;!WIpq<(i#&lYtom`=w
zX?=3PF|98gHl|xNP8d@I+xa+73Xi!QSUasOc_1BhU5g{nJuX9*#{9GiSO)d`k+Z1H
zMb6>dO5|=F`4mTi33WFd*w9v!C~Rq~N&NUr_5<#c$Kw`+&234uJGV=_5&*e<7DC|#
z(x;?qrv-;M8;09U7PeCk0@Mo@TsAbqX+pJP<P5G~j-18Voya+?J+e>~tSD&MxhLcz
zZBD<pPc8U^%#|XK)w+dJLAcaFh&Ru4pgO3&CX3NgM!x-?>`OIiEPv5fITKsjs>|K~
zv}w}F?Ma{{{pM6|9@JL(;~8z0|Kex@lG(gWP8P{_Sm3UpBLWqaT#rVyKB%nH(nyYy
zecMr&aL;I~O{Xtut4(LGCQ#-wuW}wf)>b+98rmwSZ6$$#4XcyT*wD7=Kd5#6*1-^c
z2SLk@X3`LS2V+)bDsLk@e57yjWo)VE?)0(x;=u9s-j?wjsi~RNRLfFos`bL$Ors-4
OPn;fWsnL=6@bf=vwdbAy

diff --git a/gamefiles/TEXT/italian.gxt b/gamefiles/TEXT/italian.gxt
index fd087c0dcd92a61c6f5a8acc941ed957557e58b8..407da68df450a77d75a2d738ff2aed163d3ed080 100644
GIT binary patch
delta 1066
zcmZ9~Pe@cj90%~P?t4q2x0WJUC<uwjqTSVq^x*g$-M9Ppy~pg^{BuYTQkS3zI~lx6
z!4eNa1`<Vf5rho_F+1$RN+>!>NCXvl(1hwxVc?R7ezP<0(qZ5;^M1dX`TgF!x|y83
zmAsn_XPRPQ#iH$|fXXrLG_Y}8I|B@*wOfF4n|3SE(H%o4bMraM9m;7_?pjHkaw`|K
zDfj19Y2nGU*6-IGdM+h=exyH8!cJM65{yM{I&Ati+0Jvy#qD>>l#2ED%9M)TFXTes
zpp40WC3`IBEcGL?6@$h6+WP8uX(5*}vK!VWJ`*W4#|&7WPv3wkQ@Z2^w3D${n@(##
zKrT_uwC)_yru9>4ZMsEchc*?kku%V3yUgLV=Xq(t1Chs%F#|o^<sxJ$Y)|S5OXJFe
z$Qd|ukz4S2C2}ifKN!d|Tiy-+rn2nB_Ah1Gi5q{(Uceo4SImTMaZ6C|mK&8z0g%{l
zBDCE=coc*~Ci1*iForT@+sYS%05952IIOpyQ-{hdavIYYBhy9iL~cRfjEREH3N|%+
zb&gz+n*-zXCcJaZ5q1wMWfOkZcBp_5&5LRxE10Q}?STPCPP`#|LUtO#nzD>ZY$?ks
z{ol&eX#{)X@P$|FigQp|#!nqpmhmem;}Fc^MRL+2TVa+vb_!>5a^gEKwa9R#WmpPt
zeX?ie<t286vfT9gu(I5A<Z>KEE_!6l_7i0p)A&?b#+0AO5wJcw37Gw;Y|%e>*!)dR
zdg&cJ`x7~h<!a;%hIh$%-k)7~8GC%X;nI9Px_M!c9_qcpvx^OZp8LFOVPD&3N8R{X
xb#$USTDMdkt?!*b;e(?KhiP!QD8fbndi$`zApT#UC^W@r7&OeKLR0+Or+<hF_n-g(

delta 996
zcmXxiO=uHA6bJBso86E@5B8u`2wtS97{q*3#1`yyJGRr^>@J&)O?#-9pdJLJ^w2|K
z)gD@l2f+$KDk4a+kVB!tddNjB9wa9zB8azIL@z1|iaq!yGaFd=&Fp(`=Dp4G?ewc#
z>3iwO?@xf0O2W+ob0@TO!0JiuJkXcZE&$a*?E&BqPhf<(_5|hjO=wf@-Lf|2&Ry1~
z+-I}WfhW(ZKj=8}TuNAZq+d|NMnjttT1{;_%y~@~Hm6(+zg4DG)ZZynDw?0j#mXfa
zgFUjx!jbY6+GLCQo&BY6(t+GYW<TmId=_M}+ik$|e0m3rn$l%Aq)M%nHl6nC5V=e}
z)4p+3oA$qCwdoey=e4PU)d>R^gv%UGHD{y)9tJj^E*Kc&E)OD>MPpenSPsV@#?Hf7
zi(SCVcI*LE-WwQaLf#Fj&&qNVjUUQ#5@-LBy^uTP{caP&;#NSjo9|IBhd}$FiAcC%
z;8D<vBPML#X&8NZvasw@7~;l|35QKiahgz-#m>RG5}Pi1Cw2h`>L!YU6$K4@X^mW@
z;`AF@H{o4mP9VlG*D&Fa3x^tru-jA%*@538i|J`bZoeUWft)mYc9dmIdrw(*nfj?r
zlSWS}2|w^UQ!x%J%lOe_$}+xoDv5wuyhPp^AzRTncSIK7g<SZKOCxF(rDa$aH+`~a
z+42$_fwC-Gs4B~%nd?cEcrYeo8c&pE%yvUr##Emt5wZ%M1XMmKTl5XW%vZITr2oOy
z-?4L;{~J4x^gh|<Q>QmyCLW);f9+gzGc&k5+!ZeL))sqfU0c1i?#cDVdVhi*gC29M
J-k+TP_#e?*<w*bl

diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt
index 7a71144c176ac5129e3dd0f5479d0221193c9f56..54773d07a986601e86ebb4d0f0a9e954802237ea 100644
GIT binary patch
delta 1066
zcmZ9~Pe>F|90%~P?jIsMba2UV4?<EM++zP27KlE_r#tTK%rG-sDuqEy6zrj>!_sAt
z0xLWeN^}r15Hb)FG_6Y%ED=OtU0TAZ!%9IRp85lY{ocMemlhs;es6xi_vg27v(~z@
z(RwTHmt!F?*VWA=Fuzwh1yth7X`r}IIRj)9%ALSgR|tK~%necP!ER-$UCSy{ZRwOU
z)h?eGb}X@%aiebEGO6I?ZS{c)KF=ysLEF4CZT4q{tmin@;`=jcDn;$3G?n7+TXKGQ
zOysnDAY07qD~w>7tTDSj|NN7%Bc_qv^6P=koFtlmk}aFQ0mHwA3#KPl`m0R4&F&0C
zE6|;3{=yz*nqSzjOsAO3DANTNd%_sdO=fVQ>IysDb8;wN3S*F)-0@iwlUG#0Qs}rD
zIF0h1z!@yB1nxxjRTx>O*UwgaFD*K;V?$bWqIZ*QdE6k!e}tiHTyv;*wQcEwM_t?%
zfv=mMV^LBm7D0~73zrU)buH(59)5L2V6YP-oH|tP4xB>#OyD%^Yk@Opo{Au^v%F5t
zUb|1u)8h1-oQuFZ&J0H%#FGaR*je46Ci<9Nl!3TG`6*c+9cAQFg={&Z(}=&57CF~9
zq{S`2Zb?(8u^x@WcC30=N-feNzj8oY<W~<x;V_N6<kK2i^RwL0ljt21fo+)7qV~M7
zNK0b3O}4b0I7HEv7K@%cD=ijXxEO`Yok5Xvd0JZJ6z@rk9PeQi9vh~efcDqY8vO^;
z9qTeULGK{@C2$I*Z-LV&Zjy6+WNqn1sOLyiWu_4WJU>Pcb!z+Q<E8}_+q{2i>DZg@
zhV`rC<%#if!|Hgs@zG4e21h^IXmFTtp~C~ceQ02C{-2*n#6mQ}G$N~sSd@MI2bdlD
AkpKVy

delta 996
zcmXxiPe>F|90%~P?aUJ4p+ifCa|l|hgO&To5XtO0PVO|bGsDbmu2K{sQQ)EIvV<^)
z0`<0)M8ZM_f(1c>qIQXb2#Gx;2>rpRgVG@iFNHx+zqjwr!ocVE=J$K={eH8Ho2@@L
zTB};ro=SiPf$3y`i~FRrz^Epj1GEFuc>qVGJAlWX3G_0@IzzQzPe@bkctM(K)90nB
zcH}Cz@A9*hiH0NBp@Kbk<O?czFfC05A7-WLu!TjkX&F?DnHR!TirO1tDuuU7E|xFw
zoOd6|E(?20gBbagfX=+edgTkZ&zFI%s1bO~&!GOB?0WPL*!_pQ<b<@-@?U8>t-MQt
zUZS39{qSCCS|2_rO}99gm!<};^e8xOI?OhJYQXIqp>ILEp`hPz3_oHS^xc#J%VJ|9
zb`I_LW9Kol7`p@26$J%m^1Gq-UYJkf<%Tey#P$!e8yYrw?Uw>mH*}w7SNkVi3TcYX
zDk9SfeV3BbDHWE{Xc*~ZWK*|-FvMJ^3Y!fK8Z@D5ckC?IF2&Aa=k3^e)bFY&nyhHj
zu*V;fi?liY`eszPXPNDr{kS%(!Yi0IH4vdZCj#C<`*X56G{ng1*JRh{lg8SrFwZ%)
zDa^Z^-V&xsV=|e9=ev!mq+5h}{^%iLo?kthgwJ#%Ah+mbJt`QsnZdTn1J8D7MC&#;
zPs?D%CA+%CFQEm(eAE4xh54q#*OLegzn|x{O$zfI?V&KwX?~JK$jWpQu>Mw9r*B}l
zt&3oQ{s;ILJB#%9*g0rF$(Av=JpU@ubNpU&*TQ_gtKQx8^wv~mY^u_<G*#L0tTt9j
QCFoJ;QI{&I<jK$f0W7=cqyPW_

diff --git a/utils/gxt/american.txt b/utils/gxt/american.txt
index 2507d388..66d74238 100644
--- a/utils/gxt/american.txt
+++ b/utils/gxt/american.txt
@@ -14423,6 +14423,12 @@ GAMEPAD SETTINGS
 [FEM_AUT] { aspect ratio related }
 AUTO
 
+[FEM_PED]
+PED DENSITY
+
+[FEM_CAR]
+CAR DENSITY
+
 { end of file }
 [DUMMY]
 THIS LABEL NEEDS TO BE HERE !!!
diff --git a/utils/gxt/french.txt b/utils/gxt/french.txt
index d5983e95..246600a1 100644
--- a/utils/gxt/french.txt
+++ b/utils/gxt/french.txt
@@ -14712,6 +14712,12 @@ GAMEPAD SETTINGS
 [FEM_AUT] { aspect ratio related }
 AUTO
 
+[FEM_PED]
+PED DENSITY
+
+[FEM_CAR]
+CAR DENSITY
+
 [DUMMY]
 THIS LABEL NEEDS TO BE HERE !!!
 AS THE LAST LABEL DOES NOT GET COMPILED
\ No newline at end of file
diff --git a/utils/gxt/german.txt b/utils/gxt/german.txt
index dff2382b..595d792a 100644
--- a/utils/gxt/german.txt
+++ b/utils/gxt/german.txt
@@ -14712,6 +14712,12 @@ KONTROLLEREINSTELLUNGEN
 [FEM_AUT] { aspect ratio related }
 AUTO
 
+[FEM_PED]
+PED DENSITY
+
+[FEM_CAR]
+CAR DENSITY
+
 [DUMMY]
 THIS LABEL NEEDS TO BE HERE !!!
 AS THE LAST LABEL DOES NOT GET COMPILED
diff --git a/utils/gxt/italian.txt b/utils/gxt/italian.txt
index 4773cde8..da135892 100644
--- a/utils/gxt/italian.txt
+++ b/utils/gxt/italian.txt
@@ -14721,6 +14721,12 @@ GAMEPAD SETTINGS
 [FEM_AUT] { aspect ratio related }
 AUTO
 
+[FEM_PED]
+PED DENSITY
+
+[FEM_CAR]
+CAR DENSITY
+
 [DUMMY]
 THIS LABEL NEEDS TO BE HERE !!!
 AS THE LAST LABEL DOES NOT GET COMPILED
\ No newline at end of file
diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt
index 82c1958c..07d44c4c 100644
--- a/utils/gxt/spanish.txt
+++ b/utils/gxt/spanish.txt
@@ -14407,6 +14407,12 @@ AJUSTES DE MANDO
 [FEM_AUT] { aspect ratio related }
 AUTO
 
+[FEM_PED]
+PED DENSITY
+
+[FEM_CAR]
+CAR DENSITY
+
 { end of file }
 [DUMMY]
 THIS LABEL NEEDS TO BE HERE !!!

From 3f5fdc39a5fcdf06a8dbd8ba6003b979e21107a8 Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Mon, 12 Jul 2021 03:56:07 +0300
Subject: [PATCH 8/8] Reorganize config.h

---
 .github/workflows/reVC_msvc_amd64.yml |   2 +-
 src/core/config.h                     | 180 ++++++++------------------
 2 files changed, 53 insertions(+), 129 deletions(-)

diff --git a/.github/workflows/reVC_msvc_amd64.yml b/.github/workflows/reVC_msvc_amd64.yml
index ad883d32..a00c5d2c 100644
--- a/.github/workflows/reVC_msvc_amd64.yml
+++ b/.github/workflows/reVC_msvc_amd64.yml
@@ -16,7 +16,7 @@ jobs:
     strategy:
       matrix:
         platform: [win-amd64-librw_d3d9-oal, win-amd64-librw_gl3_glfw-oal]
-        buildtype: [Debug, Release, Vanilla]
+        buildtype: [Debug, Release]
     steps:
     - name: Add msbuild to PATH
       uses: microsoft/setup-msbuild@v1.0.2
diff --git a/src/core/config.h b/src/core/config.h
index c7d01861..caa6c3e4 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -1,7 +1,9 @@
 #pragma once
 
-// disables (most) stuff that wasn't in original gta-vc.exe - check section at the bottom of this file
-//#define VANILLA_DEFINES
+// disables (most) stuff that wasn't in original gta-vc.exe
+#ifdef __MWERKS__
+#define VANILLA_DEFINES
+#endif
 
 enum Config {
 	NUMPLAYERS = 1,
@@ -154,8 +156,33 @@ enum Config {
 //#define GTA_PS2
 //#define GTA_XBOX
 
-// This enables things from the PS2 version on PC
-#define GTA_PS2_STUFF
+// Version defines
+#define GTAVC_PS2	400
+#define GTAVC_PC_10	410
+#define GTAVC_PC_11	411
+#define GTAVC_PC_JAP	412
+// TODO? maybe something for xbox or android?
+
+#define GTA_VERSION	GTAVC_PC_11
+
+// TODO(MIAMI): someone ought to find and check out uses of these defines:
+//#define GTA3_STEAM_PATCH
+//#define GTAVC_JP_PATCH
+
+#if defined GTA_PS2
+#	define GTA_PS2_STUFF
+#	define RANDOMSPLASH
+//#	define USE_CUSTOM_ALLOCATOR
+#	define VU_COLLISION
+#	define PS2_MENU
+#elif defined GTA_PC
+#	define PC_PLAYER_CONTROLS	// mouse player/cam mode
+#	define GTA_REPLAY
+#	define GTA_SCENE_EDIT
+#	define PC_MENU
+#	define PC_WATER
+#elif defined GTA_XBOX
+#endif
 
 // This is enabled for all released games.
 // any debug stuff that isn't left in any game is not in FINAL
@@ -174,22 +201,24 @@ enum Config {
 #define FINAL
 #endif
 
-// Version defines
-#define GTAVC_PS2	400
-#define GTAVC_PC_10	410
-#define GTAVC_PC_11	411
-#define GTAVC_PC_JAP	412
-// TODO? maybe something for xbox or android?
+// these are placed here to work with VANILLA_DEFINES for compatibility
+#define NO_CDCHECK // skip audio CD check
+#define DEFAULT_NATIVE_RESOLUTION // Set default video mode to your native resolution (fixes Windows 10 launch)
 
-#define GTA_VERSION	GTAVC_PC_11
-
-// TODO(MIAMI): someone ought to find and check out uses of these defines:
-//#define GTA3_STEAM_PATCH
-//#define GTAVC_JP_PATCH
+#ifdef VANILLA_DEFINES
+#define FINAL
+#define MASTER
+//#define USE_MY_DOCUMENTS
+#define THIS_IS_STUPID
+#define DONT_FIX_REPLAY_BUGS
+#define USE_TXD_CDIMAGE // generate and load textures from txd.img
+//#define USE_TEXTURE_POOL // not possible because R* used custom RW33
+#else
+// This enables things from the PS2 version on PC
+#define GTA_PS2_STUFF
 
 // quality of life fixes that should also be in FINAL
 #define NASTY_GAME	// nasty game for all languages
-#define NO_CDCHECK
 
 // those infamous texts
 #define DRAW_GAME_VERSION_TEXT
@@ -204,21 +233,10 @@ enum Config {
 //#define COMPRESSED_COL_VECTORS	// use compressed vectors for collision vertices
 //#define ANIM_COMPRESSION	// only keep most recently used anims uncompressed
 
-#if defined GTA_PS2
-#	define GTA_PS2_STUFF
-#	define RANDOMSPLASH
-//#	define USE_CUSTOM_ALLOCATOR
-#	define VU_COLLISION
-#elif defined GTA_PC
-#	ifdef GTA_PS2_STUFF
-#		define USE_PS2_RAND
-#		define RANDOMSPLASH	// use random splash as on PS2
-#		define PS2_MATFX
-#	endif
-#	define PC_PLAYER_CONTROLS	// mouse player/cam mode
-#	define GTA_REPLAY
-#	define GTA_SCENE_EDIT
-#elif defined GTA_XBOX
+#if defined GTA_PC && defined GTA_PS2_STUFF
+#	define USE_PS2_RAND
+#	define RANDOMSPLASH	// use random splash as on PS2
+#	define PS2_MATFX
 #endif
 
 #ifdef VU_COLLISION
@@ -258,7 +276,7 @@ enum Config {
 
 #define ASCII_STRCMP // use faster ascii str comparisons
 
-#if !defined _WIN32 || defined __MWERKS__ || defined __MINGW32__ || defined VANILLA_DEFINES
+#if !defined _WIN32 || defined __MINGW32__
 #undef ASCII_STRCMP
 #endif
 
@@ -293,7 +311,7 @@ enum Config {
 #endif
 
 // Water & Particle
-// #define PC_WATER
+#undef PC_WATER
 #define WATER_CHEATS
 
 //#define USE_CUTSCENE_SHADOW_FOR_PED
@@ -429,98 +447,4 @@ static_assert(false, "SUPPORT_XBOX_SCRIPT and SUPPORT_MOBILE_SCRIPT are mutually
 	#undef PS2_AUDIO_CHANNELS
 #endif
 
-// -------
-
-#if defined __MWERKS__ || defined VANILLA_DEFINES
-#define FINAL
-#undef CHATTYSPLASH
-#undef TIMEBARS
-
-#define MASTER
-#undef VALIDATE_SAVE_SIZE
-#undef NO_MOVIES
-#undef DEBUGMENU
-
-#undef DRAW_GAME_VERSION_TEXT
-
-//#undef NASTY_GAME
-//#undef NO_CDCHECK
-
-#undef GTA_PS2_STUFF
-#undef USE_PS2_RAND
-#undef RANDOMSPLASH
-#undef PS2_MATFX
-
-#undef FIX_BUGS
-#define THIS_IS_STUPID
-#undef MORE_LANGUAGES
-#undef COMPATIBLE_SAVES
-#undef FIX_INCOMPATIBLE_SAVES
-#undef LOAD_INI_SETTINGS
-
-#undef ASPECT_RATIO_SCALE
-#undef PROPER_SCALING
-//#undef DEFAULT_NATIVE_RESOLUTION
-#undef PS2_ALPHA_TEST
-#undef IMPROVED_VIDEOMODE
-#undef DISABLE_LOADING_SCREEN
-#undef DISABLE_VSYNC_ON_TEXTURE_CONVERSION
-
-#undef EXTENDED_COLOURFILTER
-#undef EXTENDED_PIPELINES
-#undef SCREEN_DROPLETS
-#undef NEW_RENDERER
-
-#undef FIX_SPRITES
-
-#define PC_WATER
-#undef WATER_CHEATS
-
-#undef USE_CUTSCENE_SHADOW_FOR_PED
-#undef DISABLE_CUTSCENE_SHADOWS
-
-#undef XINPUT
-#undef DETECT_PAD_INPUT_SWITCH
-#undef KANGAROO_CHEAT
-#undef RESTORE_ALLCARSHELI_CHEAT
-#undef BETTER_ALLCARSAREDODO_CHEAT
-#undef WALLCLIMB_CHEAT
-#undef REGISTER_START_BUTTON
-#undef BIND_VEHICLE_FIREWEAPON
-#undef BUTTON_ICONS
-
-#undef FIX_RADAR
-#undef RADIO_OFF_TEXT
-
-#undef MAP_ENHANCEMENTS
-#undef GAMEPAD_MENU
-#undef MUCH_SHORTER_OUTRO_SCREEN
-#undef CUSTOM_FRONTEND_OPTIONS
-
-#undef GRAPHICS_MENU_OPTIONS
-#undef NO_ISLAND_LOADING
-#undef CUTSCENE_BORDERS_SWITCH
-#undef MULTISAMPLING
-#undef INVERT_LOOK_FOR_PAD
-
-#undef USE_DEBUG_SCRIPT_LOADER
-#undef USE_MEASUREMENTS_IN_METERS
-#undef USE_PRECISE_MEASUREMENT_CONVERTION
-#undef SUPPORT_JAPANESE_SCRIPT
-#undef MISSION_REPLAY
-#undef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT
-#undef USE_BASIC_SCRIPT_DEBUG_OUTPUT
-
-#define DONT_FIX_REPLAY_BUGS
-
-#undef EXPLODING_AIRTRAIN
-#undef CPLANE_ROTORS
-#undef CAMERA_PICKUP
-#undef CANCELLABLE_CAR_ENTER
-#undef IMPROVED_CAMERA
-#undef FREE_CAM
-#undef BIG_IMG
-#undef PS2_AUDIO_CHANNELS
-#undef MULTITHREADED_AUDIO
-#undef RADIO_SCROLL_TO_PREV_STATION
-#endif
+#endif // VANILLA_DEFINES