diff --git a/README.md b/README.md
index 3f98c9a5..c7d83212 100644
--- a/README.md
+++ b/README.md
@@ -16,12 +16,6 @@ such that we have a working game at all times.
 - Since re3 is a DLL that works with original GTA III for now, you need Simple DLL Loader. You can get it [here](https://github.com/aap/simpledllloader).
 - Build re3 or download it from one of the above links (Debug or Release).
 - Make sure you included the re3 in `plugins.cfg` or `dlls.cfg`.
-- re3 starts the script `main_freeroam.scm` that comes along with it by default, so you should copy it to from `gamefiles/` to your game's `data/` directory.
-
-![#ffa500](https://placehold.it/15/ffa500/000000?text=+) **Notice**
-
-If you want to load original script/story, press and hold G while game is loading.
-This includes both starting new game and loading save game.
 
 ![#ffa500](https://placehold.it/15/ffa500/000000?text=+) **Notice if you will build it**
 
@@ -38,35 +32,19 @@ to reverse at the time, calling the original functions is acceptable.
 
 ### Unreversed / incomplete classes (at least the ones we know)
 ```
-cAudioManager - WIP
-CBoat
-CBrightLights
 CBulletInfo
-CCrane
-CCranes
-CCullZone
-CCullZones
-CExplosion
-CFallingGlassPane
-CGlass
-CMenuManager - WIP
-CMotionBlurStreaks
-CObject
-CPacManPickups
 CPedPath
-CRecordDataForChase
-CRoadBlocks
-CRubbish
-CSceneEdit
-CSkidmarks
-CSpecialFX
-CStats
-CTrafficLights
 CWeapon
-CWeather
 CWorld
 ```
 
+The following classes have only unused or practically unused code left:
+```
+CCullZone - only mobile stuff
+CCullZones - only mobile stuff
+CSceneEdit
+```
+
 ### Coding style
 
 I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style),
diff --git a/gamefiles/menu.txd b/gamefiles/menu.txd
new file mode 100644
index 00000000..f617bcf8
Binary files /dev/null and b/gamefiles/menu.txd differ
diff --git a/premake5.lua b/premake5.lua
index 9e3609b6..4ec2eca1 100644
--- a/premake5.lua
+++ b/premake5.lua
@@ -1,5 +1,5 @@
 workspace "re3"
-	configurations { "Debug", "Release", "ReleaseFH" }
+	configurations { "Debug", "Release", "ReleaseFH", "DebugRW", "ReleaseRW"  }
 	location "build"
 
 	files { "src/*.*" }
@@ -13,6 +13,7 @@ workspace "re3"
 	files { "src/objects/*.*" }
 	files { "src/peds/*.*" }
 	files { "src/render/*.*" }
+	files { "src/rw/*.*" }
 	files { "src/save/*.*" }
 	files { "src/skel/*.*" }
 	files { "src/skel/win/*.*" }
@@ -32,6 +33,7 @@ workspace "re3"
 	includedirs { "src/objects" }
 	includedirs { "src/peds" }
 	includedirs { "src/render" }
+	includedirs { "src/rw" }
 	includedirs { "src/save/" }
 	includedirs { "src/skel/" }
 	includedirs { "src/skel/win" }
@@ -47,6 +49,12 @@ workspace "re3"
 
 	libdirs { "dxsdk/lib" }
 	libdirs { "milessdk/lib" }
+
+	filter "configurations:DebugRW or configurations:ReleaseRW"
+	defines { "RWLIBS" }
+	libdirs { "rwsdk/lib/d3d8/release" }
+	links { "rwcore", "rpworld", "rpmatfx", "rpskin", "rphanim", "rtbmp" }
+	filter  {}
 	
     pbcommands = { 
        "setlocal EnableDelayedExpansion",
@@ -102,3 +110,15 @@ project "re3"
 		staticruntime "on"
 		targetextension ".asi"
 		setpaths("$(GTA_III_RE_DIR)/", "gta3.exe", "scripts/")
+
+	filter "configurations:DebugRW"
+		defines { "DEBUG" }
+		staticruntime "on"
+		symbols "On"
+		setpaths("$(GTA_III_RE_DIR)/", "gta3.exe", "plugins/")
+
+	filter "configurations:ReleaseRW"
+		defines { "NDEBUG" }
+		optimize "On"
+		staticruntime "on"
+		setpaths("$(GTA_III_RE_DIR)/", "gta3.exe", "plugins/")
diff --git a/src/core/CutsceneMgr.cpp b/src/animation/CutsceneMgr.cpp
similarity index 98%
rename from src/core/CutsceneMgr.cpp
rename to src/animation/CutsceneMgr.cpp
index 283f34b8..6f8e9790 100644
--- a/src/core/CutsceneMgr.cpp
+++ b/src/animation/CutsceneMgr.cpp
@@ -134,8 +134,8 @@ uint32 &CCutsceneMgr::ms_cutsceneLoadStatus = *(uint32*)0x95CB40;
 RpAtomic *
 CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data)
 {
-	float radius = RpAtomicGetBoundingSphereMacro(atomic)->radius;
-	RwV3d center = RpAtomicGetBoundingSphereMacro(atomic)->center;
+	float radius = RpAtomicGetBoundingSphere(atomic)->radius;
+	RwV3d center = RpAtomicGetBoundingSphere(atomic)->center;
 
 	for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame))
 		RwV3dTransformPoints(&center, &center, 1, RwFrameGetMatrix(frame));
@@ -326,7 +326,7 @@ CCutsceneMgr::CreateCutsceneObject(int modelId)
 
 		pModelInfo->SetColModel(pColModel);
 		clump = (RpClump*)pModelInfo->GetRwObject();
-		assert(RwObjectGetType(clump) == rpCLUMP);
+		assert(RwObjectGetType((RwObject*)clump) == rpCLUMP);
 		RpClumpForAllAtomics(clump, CalculateBoundingSphereRadiusCB, &radius);
 
 		pColModel->boundingSphere.radius = radius;
@@ -352,6 +352,7 @@ CCutsceneMgr::DeleteCutsceneData(void)
 		CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]);
 		ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject();
 		delete ms_pCutsceneObjects[ms_numCutsceneObjs];
+		ms_pCutsceneObjects[ms_numCutsceneObjs] = nil;
 	}
 	ms_numCutsceneObjs = 0;
 
@@ -409,7 +410,7 @@ CCutsceneMgr::Update(void)
 
 	if (!ms_running) return;
 
-	ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f;
+	ms_cutsceneTimer += CTimer::GetTimeStepNonClippedInSeconds();
 	if (CGeneral::faststricmp(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) {
 		if (CPad::GetPad(0)->GetCrossJustDown()
 			|| (CGame::playingIntro && CPad::GetPad(0)->GetStartJustDown())
diff --git a/src/core/CutsceneMgr.h b/src/animation/CutsceneMgr.h
similarity index 96%
rename from src/core/CutsceneMgr.h
rename to src/animation/CutsceneMgr.h
index 7b809964..3c915eea 100644
--- a/src/core/CutsceneMgr.h
+++ b/src/animation/CutsceneMgr.h
@@ -26,7 +26,7 @@ public:
 	static CDirectory *&ms_pCutsceneDir;
 	static uint32 &ms_cutsceneLoadStatus;
 
-	static void SetRunning(bool running) { ms_running = running; }
+	static void StartCutsceneProcessing() { ms_cutsceneProcessing = true; }
 	static bool IsRunning(void) { return ms_running; }
 	static bool IsCutsceneProcessing(void) { return ms_cutsceneProcessing; }
 	static bool UseLodMultiplier(void) { return ms_useLodMultiplier; }
diff --git a/src/audio/AudioCollision.cpp b/src/audio/AudioCollision.cpp
index 850fafda..fecd079e 100644
--- a/src/audio/AudioCollision.cpp
+++ b/src/audio/AudioCollision.cpp
@@ -1,403 +1,419 @@
-#include "common.h"
-#include "patcher.h"
-#include "DMAudio.h"
-#include "Entity.h"
-#include "AudioCollision.h"
-#include "AudioManager.h"
-#include "AudioSamples.h"
-#include "SurfaceTable.h"
-#include "sampman.h"
-
-const int CollisionSoundIntensity = 60;
-
-void
-cAudioCollisionManager::AddCollisionToRequestedQueue()
-{
-	int32 collisionsIndex;
-	int32 i;
-
-
-	if (m_bCollisionsInQueue < NUMAUDIOCOLLISIONS)
-		collisionsIndex = m_bCollisionsInQueue++;
-	else {
-		collisionsIndex = m_bIndicesTable[NUMAUDIOCOLLISIONS - 1];
-		if (m_sQueue.m_fDistance >= m_asCollisions1[collisionsIndex].m_fDistance) return;
-	}
-
-	m_asCollisions1[collisionsIndex] = m_sQueue;
-
-	i = 0;
-	if(collisionsIndex) {
-		while(m_asCollisions1[m_bIndicesTable[i]].m_fDistance <= m_asCollisions1[collisionsIndex].m_fDistance) {
-			if(++i >= collisionsIndex) {
-				m_bIndicesTable[i] = collisionsIndex;
-				return;
-			}
-		}
-		memmove(&m_bIndicesTable[i + 1], &m_bIndicesTable[i], NUMAUDIOCOLLISIONS - 1 - i);
-	}
-	m_bIndicesTable[i] = collisionsIndex;
-}
-
-float
-cAudioManager::GetCollisionLoopingRatio(uint32 a, uint32 b, float c) const
-{
-	return GetCollisionRatio(c, 0.0f, 0.02f, 0.02f);
-}
-
-float
-cAudioManager::GetCollisionOneShotRatio(int32 a, float b) const
-{
-	float result;
-
-	switch(a) {
-	case SURFACE_DEFAULT:
-	case SURFACE_TARMAC:
-	case SURFACE_PAVEMENT:
-	case SURFACE_STONE:
-	case SURFACE_BOLLARD: result = GetCollisionRatio(b, 10.f, 60.f, 50.f); break;
-	case SURFACE_GRASS:
-	case SURFACE_LOOSE30: result = GetCollisionRatio(b, 0.f, 2.f, 2.f); break;
-	case SURFACE_DIRT: result = GetCollisionRatio(b, 0.f, 2.f, 2.f); break;
-	case SURFACE_DIRTTRACK: result = GetCollisionRatio(b, 0.f, 2.f, 2.f); break;
-	case SURFACE_METAL6: result = GetCollisionRatio(b, 6.f, 50.f, 44.f); break;
-	case SURFACE_GLASS: result = GetCollisionRatio(b, 0.1f, 10.f, 9.9f); break;
-	case SURFACE_SCAFFOLD:
-	case SURFACE_STEEL: result = GetCollisionRatio(b, 30.f, 130.f, 100.f); break;
-	case SURFACE_METAL_DOOR: result = GetCollisionRatio(b, 20.f, 100.f, 80.f); break;
-	case SURFACE_BILLBOARD: result = GetCollisionRatio(b, 0.f, 4.f, 4.f); break;
-	case SURFACE_METAL_POLE:
-	case SURFACE_GATE: result = GetCollisionRatio(b, 1.f, 10.f, 9.f); break;
-	case SURFACE_STREET_LIGHT: result = GetCollisionRatio(b, 1.f, 10.f, 9.f); break;
-	case SURFACE_METAL14: result = GetCollisionRatio(b, 1.f, 15.f, 14.f); break;
-	case SURFACE_METAL15: result = GetCollisionRatio(b, 8.f, 50.f, 42.f); break;
-	case SURFACE_METAL_FENCE: result = GetCollisionRatio(b, 0.1f, 10.f, 9.9f); break;
-	case SURFACE_FLESH: result = GetCollisionRatio(b, 0.f, 20.f, 20.f); break;
-	case SURFACE_SAND: result = GetCollisionRatio(b, 0.f, 10.f, 10.f); break;
-	case SURFACE_PUDDLE: result = GetCollisionRatio(b, 0.f, 10.f, 10.f); break;
-	case SURFACE_WOOD: result = GetCollisionRatio(b, 1.f, 4.f, 3.f); break;
-	case SURFACE_WOOD_BOX: result = GetCollisionRatio(b, 0.1f, 5.f, 4.9f); break;
-	case SURFACE_WOOD_PLANK: result = GetCollisionRatio(b, 0.1f, 40.f, 39.9f); break;
-	case SURFACE_TIRE:
-	case SURFACE_RUBBER29: result = GetCollisionRatio(b, 0.f, 10.f, 10.f); break;
-	case SURFACE_HARD24: result = GetCollisionRatio(b, 0.1f, 4.f, 3.9f); break;
-	case SURFACE_HEDGE: result = GetCollisionRatio(b, 0.f, 0.5f, 0.5f); break;
-	case SURFACE_METAL27: result = GetCollisionRatio(b, 4.f, 40.f, 36.f); break;
-	case SURFACE_METAL28: result = GetCollisionRatio(b, 0.f, 5.f, 5.f); break;
-	default: result = 0.f; break;
-	}
-
-	return result;
-}
-
-float
-cAudioManager::GetCollisionRatio(float a, float b, float c, float d) const
-{
-	float e;
-	e = a;
-	if(a <= b) return 0.0f;
-	if(c <= a) e = c;
-	return (e - b) / d;
-}
-
-uint32
-cAudioManager::SetLoopingCollisionRequestedSfxFreqAndGetVol(cAudioCollision *audioCollision)
-{
-	uint8 surface1 = audioCollision->m_bSurface1;
-	uint8 surface2 = audioCollision->m_bSurface2;
-	int32 vol;
-	float ratio;
-
-	if(surface1 == SURFACE_GRASS || surface2 == SURFACE_GRASS || surface1 == SURFACE_HEDGE ||
-	   surface2 == SURFACE_HEDGE) {
-		ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
-		m_sQueueSample.m_nSampleIndex = SFX_RAIN;
-		m_sQueueSample.m_nFrequency = 13000.f * ratio + 35000;
-		vol = 50.f * ratio;
-	} else {
-		if(surface1 == SURFACE_PUDDLE || surface2 == SURFACE_PUDDLE) {
-			ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
-			m_sQueueSample.m_nSampleIndex = SFX_BOAT_WATER_LOOP;
-			m_sQueueSample.m_nFrequency = 6050.f * ratio + 16000;
-			vol = 30.f * ratio;
-
-		} else {
-			if(surface1 == SURFACE_DIRT || surface2 == SURFACE_DIRT || surface1 == SURFACE_DIRTTRACK ||
-			   surface2 == SURFACE_DIRTTRACK || surface1 == SURFACE_SAND || surface2 == SURFACE_SAND) {
-				ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
-				m_sQueueSample.m_nSampleIndex = SFX_GRAVEL_SKID;
-				m_sQueueSample.m_nFrequency = 6000.f * ratio + 10000;
-				vol = 50.f * ratio;
-			} else {
-				if(surface1 == SURFACE_FLESH || surface2 == SURFACE_FLESH) { return 0; }
-				ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
-				m_sQueueSample.m_nSampleIndex = SFX_SCRAPE_CAR_1;
-				m_sQueueSample.m_nFrequency = 10000.f * ratio + 10000;
-				vol = 40.f * ratio;
-			}
-		}
-	}
-	if(audioCollision->m_nBaseVolume < 2) vol = audioCollision->m_nBaseVolume * vol / 2;
-	return vol;
-}
-
-void
-cAudioManager::SetUpLoopingCollisionSound(cAudioCollision *col, uint8 counter)
-{
-	if(col->m_fIntensity2 > 0.0016f) {
-		uint8 emittingVol = SetLoopingCollisionRequestedSfxFreqAndGetVol(col);
-		if(emittingVol) {
-			m_sQueueSample.m_fDistance = Sqrt(col->m_fDistance);
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(emittingVol, CollisionSoundIntensity, m_sQueueSample.m_fDistance);
-			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_counter = counter;
-				m_sQueueSample.m_vecPos = col->m_vecPosition;
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 7;
-				m_sQueueSample.m_nLoopCount = 0;
-				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_nLoopStart =
-				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.field_48 = 4.0f;
-				m_sQueueSample.m_fSoundIntensity = CollisionSoundIntensity;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_76 = 5;
-				m_sQueueSample.m_bReverbFlag = true;
-				m_sQueueSample.m_bRequireReflection = false;
-				AddSampleToRequestedQueue();
-			}
-		}
-	}
-}
-
-void
-cAudioManager::SetUpOneShotCollisionSound(cAudioCollision *col)
-{
-	static const int32 gOneShotCol[] = {
-	    SFX_COL_TARMAC_1,   SFX_COL_TARMAC_1,   SFX_COL_GRASS_1,
-	    SFX_COL_GRAVEL_1,       SFX_COL_MUD_1,        SFX_COL_TARMAC_1,
-	    SFX_COL_CAR_1,      SFX_COL_GRASS_1,    SFX_COL_SCAFFOLD_POLE_1,
-	    SFX_COL_GARAGE_DOOR_1, SFX_COL_CAR_PANEL_1,  SFX_COL_THICK_METAL_PLATE_1,
-	    SFX_COL_SCAFFOLD_POLE_1,       SFX_COL_LAMP_POST_1,   SFX_COL_HYDRANT_1,
-	    SFX_COL_HYDRANT_1,   SFX_COL_METAL_CHAIN_FENCE_1,      SFX_COL_PED_1,
-	    SFX_COL_SAND_1,       SFX_SPLASH_1,      SFX_COL_WOOD_CRATES_1,
-	    SFX_COL_WOOD_BENCH_1,   SFX_COL_WOOD_SOLID_1, SFX_COL_GRASS_1,
-	    SFX_COL_GRASS_1,    SFX_COL_VEG_1,      SFX_COL_TARMAC_1,
-	    SFX_COL_CONTAINER_1,   SFX_COL_NEWS_VENDOR_1,   SFX_TYRE_BUMP,
-	    SFX_COL_CARDBOARD_1,      SFX_COL_TARMAC_1,   SFX_COL_GATE};
-
-	int16 s1;
-	int16 s2;
-
-	int32 emittingVol;
-	float ratio;
-
-	static uint16 counter = 28;
-
-	for(int32 i = 0; i < 2; i++) {
-		if(i) {
-			s1 = col->m_bSurface2;
-			s2 = col->m_bSurface1;
-		} else {
-			s1 = col->m_bSurface1;
-			s2 = col->m_bSurface2;
-		}
-		ratio = GetCollisionOneShotRatio(s1, col->m_fIntensity1);
-		if(s1 == SURFACE_METAL6 && s2 == SURFACE_FLESH) ratio = 0.25f * ratio;
-		if(s1 == SURFACE_METAL6 && ratio < 0.6f) {
-			s1 = SURFACE_BILLBOARD;
-			ratio = min(1.f, 2.f * ratio);
-		}
-		emittingVol = 40.f * ratio;
-		if(emittingVol) {
-			m_sQueueSample.m_fDistance = Sqrt(col->m_fDistance);
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(emittingVol, CollisionSoundIntensity, m_sQueueSample.m_fDistance);
-			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_nSampleIndex = gOneShotCol[s1];
-				switch(m_sQueueSample.m_nSampleIndex) {
-				case SFX_COL_TARMAC_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[3] % 5;
-					break;
-				case SFX_COL_CAR_PANEL_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[0] % 6;
-					break;
-				case SFX_COL_LAMP_POST_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[1] % 2;
-					break;
-				case SFX_COL_METAL_CHAIN_FENCE_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[3] % 4;
-					break;
-				case SFX_COL_PED_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[4] % 5;
-					break;
-				case SFX_COL_WOOD_CRATES_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[4] % 4;
-					break;
-				case SFX_COL_WOOD_BENCH_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[1] % 4;
-					break;
-				case SFX_COL_VEG_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[2] % 5;
-					break;
-				case SFX_COL_NEWS_VENDOR_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[2] % 3;
-					break;
-				case SFX_COL_CAR_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[1] % 5;
-					break;
-				case SFX_COL_CARDBOARD_1:
-					m_sQueueSample.m_nSampleIndex += m_anRandomTable[3] % 2;
-					break;
-				default: break;
-				}
-				switch(s1) {
-				case SURFACE_GLASS: m_sQueueSample.m_nFrequency = 13500; break;
-				case SURFACE_METAL15: m_sQueueSample.m_nFrequency = 8819; break;
-				case SURFACE_PUDDLE:
-					m_sQueueSample.m_nFrequency =
-					    2 * SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-					break;
-				case SURFACE_TIRE: m_sQueueSample.m_nFrequency = 6000; break;
-				case SURFACE_HARD24: m_sQueueSample.m_nFrequency = 8000; break;
-				default:
-					m_sQueueSample.m_nFrequency =
-					    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-					break;
-				}
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 16);
-				m_sQueueSample.m_counter = counter++;
-				if(counter >= 255) counter = 28;
-				m_sQueueSample.m_vecPos = col->m_vecPosition;
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 11;
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.field_48 = 4.0f;
-				m_sQueueSample.m_fSoundIntensity = CollisionSoundIntensity;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bReverbFlag = true;
-				m_sQueueSample.m_bRequireReflection = false;
-				AddSampleToRequestedQueue();
-			}
-		}
-	}
-}
-
-void
-cAudioManager::ServiceCollisions()
-{
-	int i, j;
-	bool someArr1[NUMAUDIOCOLLISIONS];
-	bool someArr2[NUMAUDIOCOLLISIONS];
-
-	m_sQueueSample.m_nEntityIndex = m_nCollisionEntity;
-
-	for (int i = 0; i < NUMAUDIOCOLLISIONS; i++)
-		someArr1[i] = someArr2[i] = false;
-
-	for (i = 0; i < m_sCollisionManager.m_bCollisionsInQueue; i++) {
-		for (j = 0; j < NUMAUDIOCOLLISIONS; j++) {
-			int index = m_sCollisionManager.m_bIndicesTable[i];
-			if ((m_sCollisionManager.m_asCollisions1[index].m_pEntity1 == m_sCollisionManager.m_asCollisions2[j].m_pEntity1)
-				&& (m_sCollisionManager.m_asCollisions1[index].m_pEntity2 == m_sCollisionManager.m_asCollisions2[j].m_pEntity2)
-				&& (m_sCollisionManager.m_asCollisions1[index].m_bSurface1 == m_sCollisionManager.m_asCollisions2[j].m_bSurface1)
-				&& (m_sCollisionManager.m_asCollisions1[index].m_bSurface2 == m_sCollisionManager.m_asCollisions2[j].m_bSurface2)
-				) {
-				someArr1[index] = true;
-				someArr2[j] = true;
-				m_sCollisionManager.m_asCollisions1[index].m_nBaseVolume = ++m_sCollisionManager.m_asCollisions2[j].m_nBaseVolume;
-				SetUpLoopingCollisionSound(&m_sCollisionManager.m_asCollisions1[index], j);
-				break;
-			}
-		}
-	}
-
-	for (i = 0; i < NUMAUDIOCOLLISIONS; i++) {
-		if (!someArr2[i]) {
-			m_sCollisionManager.m_asCollisions2[i].m_pEntity1 = nil;
-			m_sCollisionManager.m_asCollisions2[i].m_pEntity2 = nil;
-			m_sCollisionManager.m_asCollisions2[i].m_bSurface1 = SURFACE_DEFAULT;
-			m_sCollisionManager.m_asCollisions2[i].m_bSurface2 = SURFACE_DEFAULT;
-			m_sCollisionManager.m_asCollisions2[i].m_fIntensity2 = 0.0f;
-			m_sCollisionManager.m_asCollisions2[i].m_fIntensity1 = 0.0f;
-			m_sCollisionManager.m_asCollisions2[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f);
-			m_sCollisionManager.m_asCollisions2[i].m_fDistance = 0.0f;
-		}
-	}
-
-	for (i = 0; i < m_sCollisionManager.m_bCollisionsInQueue; i++) {
-		int index = m_sCollisionManager.m_bIndicesTable[i];
-		if (!someArr1[index]) {
-			for (j = 0; j < NUMAUDIOCOLLISIONS; j++) {
-				if (someArr2[j]) {
-					m_sCollisionManager.m_asCollisions2[j].m_nBaseVolume = 1;
-					m_sCollisionManager.m_asCollisions2[j].m_pEntity1 = m_sCollisionManager.m_asCollisions1[index].m_pEntity1;
-					m_sCollisionManager.m_asCollisions2[j].m_pEntity2 = m_sCollisionManager.m_asCollisions1[index].m_pEntity2;
-					m_sCollisionManager.m_asCollisions2[j].m_bSurface1 = m_sCollisionManager.m_asCollisions1[index].m_bSurface1;
-					m_sCollisionManager.m_asCollisions2[j].m_bSurface2 = m_sCollisionManager.m_asCollisions1[index].m_bSurface2;
-					break;
-				}
-			}
-			SetUpOneShotCollisionSound(&m_sCollisionManager.m_asCollisions1[index]);
-			SetUpLoopingCollisionSound(&m_sCollisionManager.m_asCollisions1[index], j);
-		}
-	}
-
-	for (int i = 0; i < NUMAUDIOCOLLISIONS; i++)
-		m_sCollisionManager.m_bIndicesTable[i] = NUMAUDIOCOLLISIONS;
-	m_sCollisionManager.m_bCollisionsInQueue = 0;
-}
-
-void
-cAudioManager::ReportCollision(CEntity *entity1, CEntity *entity2, uint8 surface1, uint8 surface2, float collisionPower,
-                               float velocity)
-{
-	float distSquared;
-	CVector v1;
-	CVector v2;
-
-	if(!m_bIsInitialised || m_nCollisionEntity < 0 || m_bUserPause ||
-	   (velocity < 0.0016f && collisionPower < 0.01f))
-		return;
-
-	if(entity1->IsBuilding()) {
-		v1 = v2 = entity2->GetPosition();
-	} else if(entity2->IsBuilding()) {
-		v1 = v2 = entity1->GetPosition();
-	} else {
-		v1 = entity1->GetPosition();
-		v2 = entity2->GetPosition();
-	}
-	CVector pos = (v1 + v2) * 0.5f;
-	distSquared = GetDistanceSquared(&pos);
-	if(distSquared < SQR(CollisionSoundIntensity)) {
-		m_sCollisionManager.m_sQueue.m_pEntity1 = entity1;
-		m_sCollisionManager.m_sQueue.m_pEntity2 = entity2;
-		m_sCollisionManager.m_sQueue.m_bSurface1 = surface1;
-		m_sCollisionManager.m_sQueue.m_bSurface2 = surface2;
-		m_sCollisionManager.m_sQueue.m_fIntensity1 = collisionPower;
-		m_sCollisionManager.m_sQueue.m_fIntensity2 = velocity;
-		m_sCollisionManager.m_sQueue.m_vecPosition = pos;
-		m_sCollisionManager.m_sQueue.m_fDistance = distSquared;
-		m_sCollisionManager.AddCollisionToRequestedQueue();
-	}
-}
-
-STARTPATCHES
-InjectHook(0x5685E0, &cAudioCollisionManager::AddCollisionToRequestedQueue, PATCH_JUMP);
-InjectHook(0x569060, &cAudioManager::GetCollisionOneShotRatio, PATCH_JUMP);
-InjectHook(0x5693B0, &cAudioManager::GetCollisionRatio, PATCH_JUMP);
-InjectHook(0x568410, &cAudioManager::ReportCollision, PATCH_JUMP);
-InjectHook(0x5686D0, &cAudioManager::ServiceCollisions, PATCH_JUMP);
-InjectHook(0x568E20, &cAudioManager::SetLoopingCollisionRequestedSfxFreqAndGetVol, PATCH_JUMP);
-InjectHook(0x568D30, &cAudioManager::SetUpLoopingCollisionSound, PATCH_JUMP);
-InjectHook(0x5689D0, &cAudioManager::SetUpOneShotCollisionSound, PATCH_JUMP);
-ENDPATCHES
+#include "common.h"
+#include "patcher.h"
+#include "DMAudio.h"
+#include "Entity.h"
+#include "AudioCollision.h"
+#include "AudioManager.h"
+#include "AudioSamples.h"
+#include "SurfaceTable.h"
+#include "sampman.h"
+
+const int CollisionSoundIntensity = 60;
+
+cAudioCollisionManager::cAudioCollisionManager()
+{
+	m_sQueue.m_pEntity1 = nil;
+	m_sQueue.m_pEntity2 = nil;
+	m_sQueue.m_bSurface1 = SURFACE_DEFAULT;
+	m_sQueue.m_bSurface2 = SURFACE_DEFAULT;
+	m_sQueue.m_fIntensity2 = 0.0f;
+	m_sQueue.m_fIntensity1 = 0.0f;
+	m_sQueue.m_vecPosition = CVector(0.0f, 0.0f, 0.0f);
+
+	for (int i = 0; i < NUMAUDIOCOLLISIONS; i++)
+		m_bIndicesTable[i] = NUMAUDIOCOLLISIONS;
+
+	m_bCollisionsInQueue = 0;
+}
+
+void
+cAudioCollisionManager::AddCollisionToRequestedQueue()
+{
+	int32 collisionsIndex;
+	int32 i;
+
+
+	if (m_bCollisionsInQueue < NUMAUDIOCOLLISIONS)
+		collisionsIndex = m_bCollisionsInQueue++;
+	else {
+		collisionsIndex = m_bIndicesTable[NUMAUDIOCOLLISIONS - 1];
+		if (m_sQueue.m_fDistance >= m_asCollisions1[collisionsIndex].m_fDistance) return;
+	}
+
+	m_asCollisions1[collisionsIndex] = m_sQueue;
+
+	i = 0;
+	if(collisionsIndex) {
+		while(m_asCollisions1[m_bIndicesTable[i]].m_fDistance <= m_asCollisions1[collisionsIndex].m_fDistance) {
+			if(++i >= collisionsIndex) {
+				m_bIndicesTable[i] = collisionsIndex;
+				return;
+			}
+		}
+		memmove(&m_bIndicesTable[i + 1], &m_bIndicesTable[i], NUMAUDIOCOLLISIONS - 1 - i);
+	}
+	m_bIndicesTable[i] = collisionsIndex;
+}
+
+float
+cAudioManager::GetCollisionLoopingRatio(uint32 a, uint32 b, float c) const
+{
+	return GetCollisionRatio(c, 0.0f, 0.02f, 0.02f);
+}
+
+float
+cAudioManager::GetCollisionOneShotRatio(int32 a, float b) const
+{
+	float result;
+
+	switch(a) {
+	case SURFACE_DEFAULT:
+	case SURFACE_TARMAC:
+	case SURFACE_PAVEMENT:
+	case SURFACE_STONE:
+	case SURFACE_BOLLARD: result = GetCollisionRatio(b, 10.f, 60.f, 50.f); break;
+	case SURFACE_GRASS:
+	case SURFACE_LOOSE30: result = GetCollisionRatio(b, 0.f, 2.f, 2.f); break;
+	case SURFACE_DIRT: result = GetCollisionRatio(b, 0.f, 2.f, 2.f); break;
+	case SURFACE_DIRTTRACK: result = GetCollisionRatio(b, 0.f, 2.f, 2.f); break;
+	case SURFACE_METAL6: result = GetCollisionRatio(b, 6.f, 50.f, 44.f); break;
+	case SURFACE_GLASS: result = GetCollisionRatio(b, 0.1f, 10.f, 9.9f); break;
+	case SURFACE_SCAFFOLD:
+	case SURFACE_STEEL: result = GetCollisionRatio(b, 30.f, 130.f, 100.f); break;
+	case SURFACE_METAL_DOOR: result = GetCollisionRatio(b, 20.f, 100.f, 80.f); break;
+	case SURFACE_BILLBOARD: result = GetCollisionRatio(b, 0.f, 4.f, 4.f); break;
+	case SURFACE_METAL_POLE:
+	case SURFACE_GATE: result = GetCollisionRatio(b, 1.f, 10.f, 9.f); break;
+	case SURFACE_STREET_LIGHT: result = GetCollisionRatio(b, 1.f, 10.f, 9.f); break;
+	case SURFACE_METAL14: result = GetCollisionRatio(b, 1.f, 15.f, 14.f); break;
+	case SURFACE_METAL15: result = GetCollisionRatio(b, 8.f, 50.f, 42.f); break;
+	case SURFACE_METAL_FENCE: result = GetCollisionRatio(b, 0.1f, 10.f, 9.9f); break;
+	case SURFACE_FLESH: result = GetCollisionRatio(b, 0.f, 20.f, 20.f); break;
+	case SURFACE_SAND: result = GetCollisionRatio(b, 0.f, 10.f, 10.f); break;
+	case SURFACE_PUDDLE: result = GetCollisionRatio(b, 0.f, 10.f, 10.f); break;
+	case SURFACE_WOOD: result = GetCollisionRatio(b, 1.f, 4.f, 3.f); break;
+	case SURFACE_WOOD_BOX: result = GetCollisionRatio(b, 0.1f, 5.f, 4.9f); break;
+	case SURFACE_WOOD_PLANK: result = GetCollisionRatio(b, 0.1f, 40.f, 39.9f); break;
+	case SURFACE_TIRE:
+	case SURFACE_RUBBER29: result = GetCollisionRatio(b, 0.f, 10.f, 10.f); break;
+	case SURFACE_HARD24: result = GetCollisionRatio(b, 0.1f, 4.f, 3.9f); break;
+	case SURFACE_HEDGE: result = GetCollisionRatio(b, 0.f, 0.5f, 0.5f); break;
+	case SURFACE_METAL27: result = GetCollisionRatio(b, 4.f, 40.f, 36.f); break;
+	case SURFACE_METAL28: result = GetCollisionRatio(b, 0.f, 5.f, 5.f); break;
+	default: result = 0.f; break;
+	}
+
+	return result;
+}
+
+float
+cAudioManager::GetCollisionRatio(float a, float b, float c, float d) const
+{
+	float e;
+	e = a;
+	if(a <= b) return 0.0f;
+	if(c <= a) e = c;
+	return (e - b) / d;
+}
+
+uint32
+cAudioManager::SetLoopingCollisionRequestedSfxFreqAndGetVol(cAudioCollision *audioCollision)
+{
+	uint8 surface1 = audioCollision->m_bSurface1;
+	uint8 surface2 = audioCollision->m_bSurface2;
+	int32 vol;
+	float ratio;
+
+	if(surface1 == SURFACE_GRASS || surface2 == SURFACE_GRASS || surface1 == SURFACE_HEDGE ||
+	   surface2 == SURFACE_HEDGE) {
+		ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
+		m_sQueueSample.m_nSampleIndex = SFX_RAIN;
+		m_sQueueSample.m_nFrequency = 13000.f * ratio + 35000;
+		vol = 50.f * ratio;
+	} else {
+		if(surface1 == SURFACE_PUDDLE || surface2 == SURFACE_PUDDLE) {
+			ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
+			m_sQueueSample.m_nSampleIndex = SFX_BOAT_WATER_LOOP;
+			m_sQueueSample.m_nFrequency = 6050.f * ratio + 16000;
+			vol = 30.f * ratio;
+
+		} else {
+			if(surface1 == SURFACE_DIRT || surface2 == SURFACE_DIRT || surface1 == SURFACE_DIRTTRACK ||
+			   surface2 == SURFACE_DIRTTRACK || surface1 == SURFACE_SAND || surface2 == SURFACE_SAND) {
+				ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
+				m_sQueueSample.m_nSampleIndex = SFX_GRAVEL_SKID;
+				m_sQueueSample.m_nFrequency = 6000.f * ratio + 10000;
+				vol = 50.f * ratio;
+			} else {
+				if(surface1 == SURFACE_FLESH || surface2 == SURFACE_FLESH) { return 0; }
+				ratio = GetCollisionRatio(audioCollision->m_fIntensity2, 0.0001f, 0.09f, 0.0899f);
+				m_sQueueSample.m_nSampleIndex = SFX_SCRAPE_CAR_1;
+				m_sQueueSample.m_nFrequency = 10000.f * ratio + 10000;
+				vol = 40.f * ratio;
+			}
+		}
+	}
+	if(audioCollision->m_nBaseVolume < 2) vol = audioCollision->m_nBaseVolume * vol / 2;
+	return vol;
+}
+
+void
+cAudioManager::SetUpLoopingCollisionSound(cAudioCollision *col, uint8 counter)
+{
+	if(col->m_fIntensity2 > 0.0016f) {
+		uint8 emittingVol = SetLoopingCollisionRequestedSfxFreqAndGetVol(col);
+		if(emittingVol) {
+			m_sQueueSample.m_fDistance = Sqrt(col->m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, CollisionSoundIntensity, m_sQueueSample.m_fDistance);
+			if(m_sQueueSample.m_bVolume) {
+				m_sQueueSample.m_nCounter = counter;
+				m_sQueueSample.m_vecPos = col->m_vecPosition;
+				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 7;
+				m_sQueueSample.m_nLoopCount = 0;
+				m_sQueueSample.m_bEmittingVolume = emittingVol;
+				m_sQueueSample.m_nLoopStart =
+				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd =
+				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_fSpeedMultiplier = 4.0f;
+				m_sQueueSample.m_fSoundIntensity = CollisionSoundIntensity;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
+				m_sQueueSample.m_nReleasingVolumeDivider = 5;
+				m_sQueueSample.m_bReverbFlag = true;
+				m_sQueueSample.m_bRequireReflection = false;
+				AddSampleToRequestedQueue();
+			}
+		}
+	}
+}
+
+void
+cAudioManager::SetUpOneShotCollisionSound(cAudioCollision *col)
+{
+	static const int32 gOneShotCol[] = {
+	    SFX_COL_TARMAC_1,   SFX_COL_TARMAC_1,   SFX_COL_GRASS_1,
+	    SFX_COL_GRAVEL_1,       SFX_COL_MUD_1,        SFX_COL_TARMAC_1,
+	    SFX_COL_CAR_1,      SFX_COL_GRASS_1,    SFX_COL_SCAFFOLD_POLE_1,
+	    SFX_COL_GARAGE_DOOR_1, SFX_COL_CAR_PANEL_1,  SFX_COL_THICK_METAL_PLATE_1,
+	    SFX_COL_SCAFFOLD_POLE_1,       SFX_COL_LAMP_POST_1,   SFX_COL_HYDRANT_1,
+	    SFX_COL_HYDRANT_1,   SFX_COL_METAL_CHAIN_FENCE_1,      SFX_COL_PED_1,
+	    SFX_COL_SAND_1,       SFX_SPLASH_1,      SFX_COL_WOOD_CRATES_1,
+	    SFX_COL_WOOD_BENCH_1,   SFX_COL_WOOD_SOLID_1, SFX_COL_GRASS_1,
+	    SFX_COL_GRASS_1,    SFX_COL_VEG_1,      SFX_COL_TARMAC_1,
+	    SFX_COL_CONTAINER_1,   SFX_COL_NEWS_VENDOR_1,   SFX_TYRE_BUMP,
+	    SFX_COL_CARDBOARD_1,      SFX_COL_TARMAC_1,   SFX_COL_GATE};
+
+	int16 s1;
+	int16 s2;
+
+	int32 emittingVol;
+	float ratio;
+
+	static uint16 counter = 28;
+
+	for(int32 i = 0; i < 2; i++) {
+		if(i) {
+			s1 = col->m_bSurface2;
+			s2 = col->m_bSurface1;
+		} else {
+			s1 = col->m_bSurface1;
+			s2 = col->m_bSurface2;
+		}
+		ratio = GetCollisionOneShotRatio(s1, col->m_fIntensity1);
+		if(s1 == SURFACE_METAL6 && s2 == SURFACE_FLESH) ratio = 0.25f * ratio;
+		if(s1 == SURFACE_METAL6 && ratio < 0.6f) {
+			s1 = SURFACE_BILLBOARD;
+			ratio = min(1.f, 2.f * ratio);
+		}
+		emittingVol = 40.f * ratio;
+		if(emittingVol) {
+			m_sQueueSample.m_fDistance = Sqrt(col->m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, CollisionSoundIntensity, m_sQueueSample.m_fDistance);
+			if(m_sQueueSample.m_bVolume) {
+				m_sQueueSample.m_nSampleIndex = gOneShotCol[s1];
+				switch(m_sQueueSample.m_nSampleIndex) {
+				case SFX_COL_TARMAC_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[3] % 5;
+					break;
+				case SFX_COL_CAR_PANEL_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[0] % 6;
+					break;
+				case SFX_COL_LAMP_POST_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[1] % 2;
+					break;
+				case SFX_COL_METAL_CHAIN_FENCE_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[3] % 4;
+					break;
+				case SFX_COL_PED_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[4] % 5;
+					break;
+				case SFX_COL_WOOD_CRATES_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[4] % 4;
+					break;
+				case SFX_COL_WOOD_BENCH_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[1] % 4;
+					break;
+				case SFX_COL_VEG_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[2] % 5;
+					break;
+				case SFX_COL_NEWS_VENDOR_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[2] % 3;
+					break;
+				case SFX_COL_CAR_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[1] % 5;
+					break;
+				case SFX_COL_CARDBOARD_1:
+					m_sQueueSample.m_nSampleIndex += m_anRandomTable[3] % 2;
+					break;
+				default: break;
+				}
+				switch(s1) {
+				case SURFACE_GLASS: m_sQueueSample.m_nFrequency = 13500; break;
+				case SURFACE_METAL15: m_sQueueSample.m_nFrequency = 8819; break;
+				case SURFACE_PUDDLE:
+					m_sQueueSample.m_nFrequency =
+					    2 * SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+					break;
+				case SURFACE_TIRE: m_sQueueSample.m_nFrequency = 6000; break;
+				case SURFACE_HARD24: m_sQueueSample.m_nFrequency = 8000; break;
+				default:
+					m_sQueueSample.m_nFrequency =
+					    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+					break;
+				}
+				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 16);
+				m_sQueueSample.m_nCounter = counter++;
+				if(counter >= 255) counter = 28;
+				m_sQueueSample.m_vecPos = col->m_vecPosition;
+				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 11;
+				m_sQueueSample.m_nLoopCount = 1;
+				m_sQueueSample.m_bEmittingVolume = emittingVol;
+				m_sQueueSample.m_nLoopStart = 0;
+				m_sQueueSample.m_nLoopEnd = -1;
+				m_sQueueSample.m_fSpeedMultiplier = 4.0f;
+				m_sQueueSample.m_fSoundIntensity = CollisionSoundIntensity;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_bReverbFlag = true;
+				m_sQueueSample.m_bRequireReflection = false;
+				AddSampleToRequestedQueue();
+			}
+		}
+	}
+}
+
+void
+cAudioManager::ServiceCollisions()
+{
+	int i, j;
+	bool someArr1[NUMAUDIOCOLLISIONS];
+	bool someArr2[NUMAUDIOCOLLISIONS];
+
+	m_sQueueSample.m_nEntityIndex = m_nCollisionEntity;
+
+	for (int i = 0; i < NUMAUDIOCOLLISIONS; i++)
+		someArr1[i] = someArr2[i] = false;
+
+	for (i = 0; i < m_sCollisionManager.m_bCollisionsInQueue; i++) {
+		for (j = 0; j < NUMAUDIOCOLLISIONS; j++) {
+			int index = m_sCollisionManager.m_bIndicesTable[i];
+			if ((m_sCollisionManager.m_asCollisions1[index].m_pEntity1 == m_sCollisionManager.m_asCollisions2[j].m_pEntity1)
+				&& (m_sCollisionManager.m_asCollisions1[index].m_pEntity2 == m_sCollisionManager.m_asCollisions2[j].m_pEntity2)
+				&& (m_sCollisionManager.m_asCollisions1[index].m_bSurface1 == m_sCollisionManager.m_asCollisions2[j].m_bSurface1)
+				&& (m_sCollisionManager.m_asCollisions1[index].m_bSurface2 == m_sCollisionManager.m_asCollisions2[j].m_bSurface2)
+				) {
+				someArr1[index] = true;
+				someArr2[j] = true;
+				m_sCollisionManager.m_asCollisions1[index].m_nBaseVolume = ++m_sCollisionManager.m_asCollisions2[j].m_nBaseVolume;
+				SetUpLoopingCollisionSound(&m_sCollisionManager.m_asCollisions1[index], j);
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < NUMAUDIOCOLLISIONS; i++) {
+		if (!someArr2[i]) {
+			m_sCollisionManager.m_asCollisions2[i].m_pEntity1 = nil;
+			m_sCollisionManager.m_asCollisions2[i].m_pEntity2 = nil;
+			m_sCollisionManager.m_asCollisions2[i].m_bSurface1 = SURFACE_DEFAULT;
+			m_sCollisionManager.m_asCollisions2[i].m_bSurface2 = SURFACE_DEFAULT;
+			m_sCollisionManager.m_asCollisions2[i].m_fIntensity2 = 0.0f;
+			m_sCollisionManager.m_asCollisions2[i].m_fIntensity1 = 0.0f;
+			m_sCollisionManager.m_asCollisions2[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f);
+			m_sCollisionManager.m_asCollisions2[i].m_fDistance = 0.0f;
+		}
+	}
+
+	for (i = 0; i < m_sCollisionManager.m_bCollisionsInQueue; i++) {
+		int index = m_sCollisionManager.m_bIndicesTable[i];
+		if (!someArr1[index]) {
+			for (j = 0; j < NUMAUDIOCOLLISIONS; j++) {
+				if (someArr2[j]) {
+					m_sCollisionManager.m_asCollisions2[j].m_nBaseVolume = 1;
+					m_sCollisionManager.m_asCollisions2[j].m_pEntity1 = m_sCollisionManager.m_asCollisions1[index].m_pEntity1;
+					m_sCollisionManager.m_asCollisions2[j].m_pEntity2 = m_sCollisionManager.m_asCollisions1[index].m_pEntity2;
+					m_sCollisionManager.m_asCollisions2[j].m_bSurface1 = m_sCollisionManager.m_asCollisions1[index].m_bSurface1;
+					m_sCollisionManager.m_asCollisions2[j].m_bSurface2 = m_sCollisionManager.m_asCollisions1[index].m_bSurface2;
+					break;
+				}
+			}
+			SetUpOneShotCollisionSound(&m_sCollisionManager.m_asCollisions1[index]);
+			SetUpLoopingCollisionSound(&m_sCollisionManager.m_asCollisions1[index], j);
+		}
+	}
+
+	for (int i = 0; i < NUMAUDIOCOLLISIONS; i++)
+		m_sCollisionManager.m_bIndicesTable[i] = NUMAUDIOCOLLISIONS;
+	m_sCollisionManager.m_bCollisionsInQueue = 0;
+}
+
+void
+cAudioManager::ReportCollision(CEntity *entity1, CEntity *entity2, uint8 surface1, uint8 surface2, float collisionPower,
+                               float velocity)
+{
+	float distSquared;
+	CVector v1;
+	CVector v2;
+
+	if(!m_bIsInitialised || m_nCollisionEntity < 0 || m_bUserPause ||
+	   (velocity < 0.0016f && collisionPower < 0.01f))
+		return;
+
+	if(entity1->IsBuilding()) {
+		v1 = v2 = entity2->GetPosition();
+	} else if(entity2->IsBuilding()) {
+		v1 = v2 = entity1->GetPosition();
+	} else {
+		v1 = entity1->GetPosition();
+		v2 = entity2->GetPosition();
+	}
+	CVector pos = (v1 + v2) * 0.5f;
+	distSquared = GetDistanceSquared(&pos);
+	if(distSquared < SQR(CollisionSoundIntensity)) {
+		m_sCollisionManager.m_sQueue.m_pEntity1 = entity1;
+		m_sCollisionManager.m_sQueue.m_pEntity2 = entity2;
+		m_sCollisionManager.m_sQueue.m_bSurface1 = surface1;
+		m_sCollisionManager.m_sQueue.m_bSurface2 = surface2;
+		m_sCollisionManager.m_sQueue.m_fIntensity1 = collisionPower;
+		m_sCollisionManager.m_sQueue.m_fIntensity2 = velocity;
+		m_sCollisionManager.m_sQueue.m_vecPosition = pos;
+		m_sCollisionManager.m_sQueue.m_fDistance = distSquared;
+		m_sCollisionManager.AddCollisionToRequestedQueue();
+	}
+}
+
+STARTPATCHES
+InjectHook(0x5685E0, &cAudioCollisionManager::AddCollisionToRequestedQueue, PATCH_JUMP);
+InjectHook(0x569060, &cAudioManager::GetCollisionOneShotRatio, PATCH_JUMP);
+InjectHook(0x5693B0, &cAudioManager::GetCollisionRatio, PATCH_JUMP);
+InjectHook(0x568410, &cAudioManager::ReportCollision, PATCH_JUMP);
+InjectHook(0x5686D0, &cAudioManager::ServiceCollisions, PATCH_JUMP);
+InjectHook(0x568E20, &cAudioManager::SetLoopingCollisionRequestedSfxFreqAndGetVol, PATCH_JUMP);
+InjectHook(0x568D30, &cAudioManager::SetUpLoopingCollisionSound, PATCH_JUMP);
+InjectHook(0x5689D0, &cAudioManager::SetUpOneShotCollisionSound, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/audio/AudioCollision.h b/src/audio/AudioCollision.h
index cf201735..a21bbfdc 100644
--- a/src/audio/AudioCollision.h
+++ b/src/audio/AudioCollision.h
@@ -1,36 +1,36 @@
-#pragma once
-
-#define NUMAUDIOCOLLISIONS 10
-
-class cAudioCollision
-{
-public:
-	CEntity *m_pEntity1;
-	CEntity *m_pEntity2;
-	uint8 m_bSurface1;
-	uint8 m_bSurface2;
-	float m_fIntensity1;
-	float m_fIntensity2;
-	CVector m_vecPosition;
-	float m_fDistance;
-	int32 m_nBaseVolume;
-
-	// no methods
-};
-
-static_assert(sizeof(cAudioCollision) == 40, "cAudioCollision: error");
-
-class cAudioCollisionManager
-{
-public:
-	cAudioCollision m_asCollisions1[NUMAUDIOCOLLISIONS];
-	cAudioCollision m_asCollisions2[NUMAUDIOCOLLISIONS];
-	uint8 m_bIndicesTable[NUMAUDIOCOLLISIONS];
-	uint8 m_bCollisionsInQueue;
-	cAudioCollision m_sQueue;
-
-	// reversed all methods
-	void AddCollisionToRequestedQueue(); /// ok
-};
-
+#pragma once
+
+#define NUMAUDIOCOLLISIONS 10
+
+class cAudioCollision
+{
+public:
+	CEntity *m_pEntity1;
+	CEntity *m_pEntity2;
+	uint8 m_bSurface1;
+	uint8 m_bSurface2;
+	float m_fIntensity1;
+	float m_fIntensity2;
+	CVector m_vecPosition;
+	float m_fDistance;
+	int32 m_nBaseVolume;
+
+	// no methods
+};
+
+static_assert(sizeof(cAudioCollision) == 40, "cAudioCollision: error");
+
+class cAudioCollisionManager
+{
+public:
+	cAudioCollision m_asCollisions1[NUMAUDIOCOLLISIONS];
+	cAudioCollision m_asCollisions2[NUMAUDIOCOLLISIONS];
+	uint8 m_bIndicesTable[NUMAUDIOCOLLISIONS];
+	uint8 m_bCollisionsInQueue;
+	cAudioCollision m_sQueue;
+
+	cAudioCollisionManager();
+	void AddCollisionToRequestedQueue();
+};
+
 static_assert(sizeof(cAudioCollisionManager) == 852, "cAudioCollisionManager: error");
\ No newline at end of file
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
index 8e8d024a..1d2835cf 100644
--- a/src/audio/AudioManager.cpp
+++ b/src/audio/AudioManager.cpp
@@ -1,8 +1,7 @@
-#include "common.h"
+#include "common.h"
 #include "patcher.h"
-#include "General.h"
-#include "audio_enums.h"
 
+#include "audio_enums.h"
 #include "AudioManager.h"
 
 #include "Automobile.h"
@@ -13,14 +12,15 @@
 #include "DMAudio.h"
 #include "Entity.h"
 #include "Explosion.h"
+#include "Fire.h"
 #include "Garages.h"
+#include "General.h"
 #include "HandlingMgr.h"
 #include "Heli.h"
 #include "ModelIndices.h"
 #include "MusicManager.h"
 #include "Pad.h"
 #include "Ped.h"
-#include "Fire.h"
 #include "Physical.h"
 #include "Placeable.h"
 #include "Plane.h"
@@ -39,20 +39,19 @@
 #include "ZoneCull.h"
 #include "sampman.h"
 
-cAudioManager &AudioManager = *(cAudioManager *)0x880FC0;
-uint32 &gPornNextTime = *(uint32*)0x6508A0;
-uint32 &gSawMillNextTime = *(uint32*)0x6508A4;
-uint32 &gShopNextTime = *(uint32*)0x6508A8;
-uint32 &gAirportNextTime = *(uint32*)0x6508AC;
-uint32 &gCinemaNextTime = *(uint32*)0x6508B0;
-uint32 &gDocksNextTime = *(uint32*)0x6508B4;
-uint32 &gHomeNextTime = *(uint32*)0x6508B8;
-uint32 &gCellNextTime = *(uint32*)0x6508BC;
-uint32 &gNextCryTime = *(uint32*)0x6508C0;
-uint8 &jumboVolOffset = *(uint8 *)0x6508ED;
-uint8 &gJumboVolOffsetPercentage = *(uint8 *)0x6508ED;
-bool &bPlayerJustEnteredCar = *(bool *)0x6508C4;
-bool &g_bMissionAudioLoadFailed = *(bool *)0x95CD8E;
+cAudioManager AudioManager;
+uint32 gPornNextTime;            // = *(uint32*)0x6508A0;
+uint32 gSawMillNextTime;         // = *(uint32*)0x6508A4;
+uint32 gShopNextTime;            // = *(uint32*)0x6508A8;
+uint32 gAirportNextTime;         // = *(uint32*)0x6508AC;
+uint32 gCinemaNextTime;          //= *(uint32*)0x6508B0;
+uint32 gDocksNextTime;           // = *(uint32*)0x6508B4;
+uint32 gHomeNextTime;            // = *(uint32*)0x6508B8;
+uint32 gCellNextTime;            // = *(uint32*)0x6508BC;
+uint32 gNextCryTime;             // = *(uint32*)0x6508C0;
+uint8 gJumboVolOffsetPercentage; // = *(uint8 *)0x6508ED;
+bool bPlayerJustEnteredCar;      // = *(bool *)0x6508C4;
+bool g_bMissionAudioLoadFailed;  // = *(bool *)0x95CD8E;
 
 const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples);
 const int policeChannel = channels + 1;
@@ -70,39 +69,46 @@ const int rainOnVehicleIntensity = 22;
 const int reverseGearIntensity = 30;
 const int engineDamageIntensity = 40;
 
-
 const bool hornPatternsArray[8][44] = {
-    {false, false, true,  true,  true,  true,  true,  true,  true, true, true,  true,  true,  true, true,
-     true,  true,  false, false, false, false, false, false, true, true, true,  true,  true,  true, true,
-     true,  true,  true,  true,  true,  true,  true,  true,  true, true, false, false, false, false},
+    {false, false, true, true, true, true, true,  true,  true,  true,  true,
+     true,  true,  true, true, true, true, false, false, false, false, false,
+     false, true,  true, true, true, true, true,  true,  true,  true,  true,
+     true,  true,  true, true, true, true, true,  false, false, false, false},
     {false, false, true, true, true, true, true, true, true, true, true, true, true,  true, true,
      true,  true,  true, true, true, true, true, true, true, true, true, true, true,  true, true,
      true,  true,  true, true, true, true, true, true, true, true, true, true, false, false},
-    {false, false, true, true, true, true, true,  true,  true,  true, true, true, false, false, false,
-     false, true,  true, true, true, true, false, false, false, true, true, true, true,  true,  true,
-     true,  true,  true, true, true, true, true,  true,  true,  true, true, true, true,  false},
-    {false, false, true, true, true, true, true, false, false, true, true, true, true,  true,  false,
-     false, false, true, true, true, true, true, true,  true,  true, true, true, false, false, false,
-     true,  true,  true, true, true, true, true, true,  true,  true, true, true, true,  false},
-    {false, false, true,  true,  true,  true,  true,  true,  true,  true,  true,  false, false, false, false,
-     false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
-     false, false, false, false, false, false, false, false, false, false, false, false, false, false},
-    {false, false, true,  true,  true,  false, false, false, true,  true,  true,  false, false, false, false,
-     false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
-     false, false, false, false, false, false, false, false, false, false, false, false, false, false},
-    {false, false, true, true,  true,  true, false, false, false, false, true, true,  true,  false, false,
-     true,  true,  true, false, false, true, true,  true,  true,  true,  true, false, false, false, false,
-     false, true,  true, true,  true,  true, true,  true,  true,  true,  true, true,  false, false},
-    {false, false, true, true, true, true, false, false, true,  true,  true,  true,  true,  false, false,
-     false, true,  true, true, true, true, true,  false, false, false, false, true,  true,  true,  true,
-     true,  true,  true, true, true, true, true,  true,  true,  false, false, false, false, false},
+    {false, false, true,  true,  true,  true, true, true, true, true, true,
+     true,  false, false, false, false, true, true, true, true, true, false,
+     false, false, true,  true,  true,  true, true, true, true, true, true,
+     true,  true,  true,  true,  true,  true, true, true, true, true, false},
+    {false, false, true, true,  true,  true,  true,  false, false, true, true,
+     true,  true,  true, false, false, false, true,  true,  true,  true, true,
+     true,  true,  true, true,  true,  false, false, false, true,  true, true,
+     true,  true,  true, true,  true,  true,  true,  true,  true,  true, false},
+    {false, false, true,  true,  true,  true,  true,  true,  true,  true,  true,
+     false, false, false, false, false, false, false, false, false, false, false,
+     false, false, false, false, false, false, false, false, false, false, false,
+     false, false, false, false, false, false, false, false, false, false, false},
+    {false, false, true,  true,  true,  false, false, false, true,  true,  true,
+     false, false, false, false, false, false, false, false, false, false, false,
+     false, false, false, false, false, false, false, false, false, false, false,
+     false, false, false, false, false, false, false, false, false, false, false},
+    {false, false, true,  true,  true,  true,  false, false, false, false, true,
+     true,  true,  false, false, true,  true,  true,  false, false, true,  true,
+     true,  true,  true,  true,  false, false, false, false, false, true,  true,
+     true,  true,  true,  true,  true,  true,  true,  true,  true,  false, false},
+    {false, false, true,  true,  true,  true, false, false, true,  true,  true,
+     true,  true,  false, false, false, true, true,  true,  true,  true,  true,
+     false, false, false, false, true,  true, true,  true,  true,  true,  true,
+     true,  true,  true,  true,  true,  true, false, false, false, false, false},
 };
 
 const int totalAudioEntitiesSlots = 200;
 
-const uint8 panTable[64]{0,  3,  8,  12, 16, 19, 22, 24, 26, 28, 30, 31, 33, 34, 36, 37, 39, 40, 41, 42, 44, 45,
-                             46, 47, 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59, 59,
-                             59, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63};
+const uint8 panTable[64]{0,  3,  8,  12, 16, 19, 22, 24, 26, 28, 30, 31, 33, 34, 36, 37,
+                         39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 53,
+                         54, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59, 59, 59, 60, 60, 61,
+                         61, 61, 61, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63};
 
 // TODO: where is this used? Is this the right file?
 enum eVehicleModel {
@@ -178,37 +184,60 @@ enum eVehicleModel {
 	CAR159,
 };
 
+enum PLAY_STATUS : uint8 {
+	PLAY_STATUS_STOPPED = 0,
+	PLAY_STATUS_PLAYING = 1,
+	PLAY_STATUS_FINISHED = 2
+};
+
+enum LOADING_STATUS : uint8 { LOADING_STATUS_NOT_LOADED = 0, LOADING_STATUS_LOADED = 1 };
+
+cPedComments::cPedComments()
+{
+	for (int i = 0; i < NUM_PED_COMMENTS_SLOTS; i++)
+		for (int j = 0; j < NUM_PED_COMMENTS_BANKS; j++) {
+			m_asPedComments[j][i].m_nProcess = -1;
+			m_nIndexMap[j][i] = NUM_PED_COMMENTS_SLOTS;
+		}
+
+	for (int i = 0; i < NUM_PED_COMMENTS_BANKS; i++)
+		m_nCommentsInBank[i] = 0;
+	m_nActiveBank = 0;
+}
+
 void
 cPedComments::Add(tPedComment *com)
 {
 	uint8 index;
 
-	if(nrOfCommentsInBank[activeBank] >= NUM_PED_COMMENTS_SLOTS) {
-		index = indexMap[activeBank][NUM_PED_COMMENTS_SLOTS - 1];
-		if(m_asPedComments[activeBank][index].m_bVolume > com->m_bVolume) return;
+	if(m_nCommentsInBank[m_nActiveBank] >= NUM_PED_COMMENTS_SLOTS) {
+		index = m_nIndexMap[m_nActiveBank][NUM_PED_COMMENTS_SLOTS - 1];
+		if(m_asPedComments[m_nActiveBank][index].m_bVolume > com->m_bVolume) return;
 	} else {
-		index = nrOfCommentsInBank[activeBank]++;
+		index = m_nCommentsInBank[m_nActiveBank]++;
 	}
 
-	m_asPedComments[activeBank][index].m_nSampleIndex = com->m_nSampleIndex;
-	m_asPedComments[activeBank][index].m_entityIndex = com->m_entityIndex;
-	m_asPedComments[activeBank][index].m_vecPos = com->m_vecPos;
-	m_asPedComments[activeBank][index].m_fDistance = com->m_fDistance;
-	m_asPedComments[activeBank][index].m_bVolume = com->m_bVolume;
+	m_asPedComments[m_nActiveBank][index].m_nSampleIndex = com->m_nSampleIndex;
+	m_asPedComments[m_nActiveBank][index].m_nEntityIndex = com->m_nEntityIndex;
+	m_asPedComments[m_nActiveBank][index].m_vecPos = com->m_vecPos;
+	m_asPedComments[m_nActiveBank][index].m_fDistance = com->m_fDistance;
+	m_asPedComments[m_nActiveBank][index].m_bVolume = com->m_bVolume;
 
 	uint32 i = 0;
 	if(index != 0) {
 		for(i = 0; i < index; i++) {
-			if(m_asPedComments[activeBank][indexMap[activeBank][i]].m_bVolume <
-			   m_asPedComments[activeBank][index].m_bVolume) {
+			if(m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][i]].m_bVolume <
+			   m_asPedComments[m_nActiveBank][index].m_bVolume) {
 				break;
 			}
 		}
 
-		if(i < index) memmove(&indexMap[activeBank][i + 1], &indexMap[activeBank][i], NUM_PED_COMMENTS_SLOTS -1 - i);
+		if(i < index)
+			memmove(&m_nIndexMap[m_nActiveBank][i + 1], &m_nIndexMap[m_nActiveBank][i],
+			        NUM_PED_COMMENTS_SLOTS - 1 - i);
 	}
 
-	indexMap[activeBank][i] = index;
+	m_nIndexMap[m_nActiveBank][i] = index;
 }
 
 void
@@ -222,36 +251,42 @@ cPedComments::Process()
 	static const int policeHeliIntensity = 400;
 
 	if(!AudioManager.m_bUserPause) {
-		if(nrOfCommentsInBank[activeBank]) {
-			sampleIndex = m_asPedComments[activeBank][indexMap[activeBank][0]].m_nSampleIndex;
-			if(!SampleManager.IsPedCommentLoaded(sampleIndex)) SampleManager.LoadPedComment(sampleIndex);
+		if(m_nCommentsInBank[m_nActiveBank]) {
+			sampleIndex = m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][0]]
+			                  .m_nSampleIndex;
+			if(!SampleManager.IsPedCommentLoaded(sampleIndex))
+				SampleManager.LoadPedComment(sampleIndex);
 
 			AudioManager.m_sQueueSample.m_nEntityIndex =
-			    m_asPedComments[activeBank][indexMap[activeBank][0]].m_entityIndex;
-			AudioManager.m_sQueueSample.m_counter = 0;
+			    m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][0]]
+			        .m_nEntityIndex;
+			AudioManager.m_sQueueSample.m_nCounter = 0;
 			AudioManager.m_sQueueSample.m_nSampleIndex = sampleIndex;
 			AudioManager.m_sQueueSample.m_bBankIndex = SAMPLEBANK_PED;
-			AudioManager.m_sQueueSample.field_16 = 3;
+			AudioManager.m_sQueueSample.m_nReleasingVolumeModificator = 3;
 			AudioManager.m_sQueueSample.m_bVolume =
-			    m_asPedComments[activeBank][indexMap[activeBank][0]].m_bVolume;
+			    m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][0]].m_bVolume;
 			AudioManager.m_sQueueSample.m_fDistance =
-			    m_asPedComments[activeBank][indexMap[activeBank][0]].m_fDistance;
+			    m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][0]]
+			        .m_fDistance;
 			AudioManager.m_sQueueSample.m_nLoopCount = 1;
 			AudioManager.m_sQueueSample.m_nLoopStart = 0;
 			AudioManager.m_sQueueSample.m_nLoopEnd = -1;
 			AudioManager.m_sQueueSample.m_bEmittingVolume = maxVolume;
-			AudioManager.m_sQueueSample.field_48 = 3.0f;
+			AudioManager.m_sQueueSample.m_fSpeedMultiplier = 3.0f;
 			switch(sampleIndex) {
 			case SFX_POLICE_HELI_1:
 			case SFX_POLICE_HELI_2:
 			case SFX_POLICE_HELI_3:
 				AudioManager.m_sQueueSample.m_fSoundIntensity = policeHeliIntensity;
 				break;
-			default: AudioManager.m_sQueueSample.m_fSoundIntensity = defaultIntensity; break;
+			default:
+				AudioManager.m_sQueueSample.m_fSoundIntensity = defaultIntensity;
+				break;
 			}
-			AudioManager.m_sQueueSample.field_56 = 1;
+			AudioManager.m_sQueueSample.m_bReleasingSoundFlag = true;
 			AudioManager.m_sQueueSample.m_vecPos =
-			    m_asPedComments[activeBank][indexMap[activeBank][0]].m_vecPos;
+			    m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][0]].m_vecPos;
 
 			if(sampleIndex >= SFX_AMMU_D && sampleIndex <= SFX_AMMU_F) {
 				AudioManager.m_sQueueSample.m_bReverbFlag = false;
@@ -261,78 +296,122 @@ cPedComments::Process()
 				AudioManager.m_sQueueSample.m_bRequireReflection = true;
 			}
 
-			AudioManager.m_sQueueSample.m_bIsDistant = false;
+			AudioManager.m_sQueueSample.m_bIs2D = false;
 			AudioManager.m_sQueueSample.m_nFrequency =
-			    SampleManager.GetSampleBaseFrequency(AudioManager.m_sQueueSample.m_nSampleIndex) +
+			    SampleManager.GetSampleBaseFrequency(
+			        AudioManager.m_sQueueSample.m_nSampleIndex) +
 			    AudioManager.RandomDisplacement(750);
-			if(CTimer::GetIsSlowMotionActive()) AudioManager.m_sQueueSample.m_nFrequency /= 2;
-			m_asPedComments[activeBank][indexMap[activeBank][0]].field_25 = -1;
+			if(CTimer::GetIsSlowMotionActive())
+				AudioManager.m_sQueueSample.m_nFrequency /= 2;
+			m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][0]].m_nProcess =
+			    -1;
 			AudioManager.AddSampleToRequestedQueue();
 		}
 
 		// Switch bank
-		if(activeBank) {
+		if(m_nActiveBank) {
 			actualUsedBank = SAMPLEBANK_PED;
-			activeBank = SAMPLEBANK_MAIN;
+			m_nActiveBank = SAMPLEBANK_MAIN;
 		} else {
 			actualUsedBank = SAMPLEBANK_MAIN;
-			activeBank = SAMPLEBANK_PED;
+			m_nActiveBank = SAMPLEBANK_PED;
 		}
 		comment = m_asPedComments[actualUsedBank];
-		for(uint32 i = 0; i < nrOfCommentsInBank[actualUsedBank]; i++) {
-			if(m_asPedComments[actualUsedBank][indexMap[actualUsedBank][i]].field_25 > 0) {
-				--m_asPedComments[actualUsedBank][indexMap[actualUsedBank][i]].field_25;
-				Add(&comment[indexMap[actualUsedBank][i]]);
+		for(uint32 i = 0; i < m_nCommentsInBank[actualUsedBank]; i++) {
+			if(m_asPedComments[actualUsedBank][m_nIndexMap[actualUsedBank][i]]
+			       .m_nProcess > 0) {
+				--m_asPedComments[actualUsedBank][m_nIndexMap[actualUsedBank][i]]
+				      .m_nProcess;
+				Add(&comment[m_nIndexMap[actualUsedBank][i]]);
 			}
 		}
 
-		for(uint32 i = 0; i < NUM_PED_COMMENTS_SLOTS; i++) { indexMap[actualUsedBank][i] = NUM_PED_COMMENTS_SLOTS; }
-		nrOfCommentsInBank[actualUsedBank] = 0;
+		for(uint32 i = 0; i < NUM_PED_COMMENTS_SLOTS; i++) {
+			m_nIndexMap[actualUsedBank][i] = NUM_PED_COMMENTS_SLOTS;
+		}
+		m_nCommentsInBank[actualUsedBank] = 0;
 	}
 }
 
+cAudioManager::cAudioManager()
+{
+	m_bIsInitialised = false;
+	field_1 = 1;
+	m_fSpeedOfSound = 6.86f;
+	m_bTimeSpent = 50;
+	m_bActiveSamples = NUM_SOUNDS_SAMPLES_SLOTS;
+	m_bActiveSampleQueue = 1;
+	ClearRequestedQueue();
+	m_bActiveSampleQueue = 0;
+	ClearRequestedQueue();
+	ClearActiveSamples();
+	GenerateIntegerRandomNumberTable();
+	field_4 = 0;
+	m_bDynamicAcousticModelingStatus = 1;
+
+	for(int i = 0; i < NUM_AUDIOENTITIES; i++) {
+		m_asAudioEntities[i].m_bIsUsed = false;
+		m_anAudioEntityIndices[i] = NUM_AUDIOENTITIES;
+	}
+	m_nAudioEntitiesTotal = 0;
+	m_FrameCounter = 0;
+	m_bFifthFrameFlag = 0;
+	m_bTimerJustReset = 0;
+	m_nTimer = 0;
+}
+
+cAudioManager::~cAudioManager()
+{
+	if(m_bIsInitialised) Terminate();
+}
+
 void
 cAudioManager::AddDetailsToRequestedOrderList(uint8 sample)
 {
 	uint32 i = 0;
 	if(sample != 0) {
 		for(; i < sample; i++) {
-			if(m_asSamples[m_bActiveSampleQueue][m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]]
-			       .calculatedVolume > m_asSamples[m_bActiveSampleQueue][sample].calculatedVolume)
+			if(m_asSamples[m_bActiveSampleQueue]
+			              [m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]]
+			                  .m_nCalculatedVolume >
+			   m_asSamples[m_bActiveSampleQueue][sample].m_nCalculatedVolume)
 				break;
 		}
 		if(i < sample) {
 			memmove(&m_abSampleQueueIndexTable[m_bActiveSampleQueue][i + 1],
-			        &m_abSampleQueueIndexTable[m_bActiveSampleQueue][i], m_bActiveSamples - i - 1);
+			        &m_abSampleQueueIndexTable[m_bActiveSampleQueue][i],
+			        m_bActiveSamples - i - 1);
 		}
 	}
 	m_abSampleQueueIndexTable[m_bActiveSampleQueue][i] = sample;
 }
 
 void
-cAudioManager::AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 unk1, uint8 counter,
-                                  bool notLooping)
+cAudioManager::AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 unk1,
+                                  uint8 counter, bool notLooping)
 {
 	m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, 50.f, m_sQueueSample.m_fDistance);
 	if(m_sQueueSample.m_bVolume) {
-		m_sQueueSample.m_counter = counter;
+		m_sQueueSample.m_nCounter = counter;
 		m_sQueueSample.m_nSampleIndex = sample;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = false;
-		m_sQueueSample.field_16 = 0;
+		m_sQueueSample.m_bIs2D = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 0;
 		m_sQueueSample.m_nFrequency = freq;
 		if(notLooping) {
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_76 = 8;
+			m_sQueueSample.m_nReleasingVolumeDivider = 8;
 		} else {
 			m_sQueueSample.m_nLoopCount = 1;
 		}
 		m_sQueueSample.m_bEmittingVolume = emittingVolume;
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_48 = 6.0f;
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 		m_sQueueSample.m_fSoundIntensity = 50.0f;
-		m_sQueueSample.field_56 = 0;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
 		m_sQueueSample.m_bReverbFlag = true;
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
@@ -354,18 +433,20 @@ cAudioManager::AddReflectionsToRequestedQueue()
 			if(m_sQueueSample.m_bLoopsRemaining > 5) {
 				m_sQueueSample.m_fDistance = m_afReflectionsDistances[i];
 				m_sQueueSample.m_bEmittingVolume = emittingVolume;
-				m_sQueueSample.m_bVolume = ComputeVolume(
-				    emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity,
+				                  m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume > emittingVolume >> 4) {
-					m_sQueueSample.m_counter += ((i + 1) << 8);
+					m_sQueueSample.m_nCounter += ((i + 1) << 8);
 					if(m_sQueueSample.m_nLoopCount) {
-						noise = RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+						noise = RandomDisplacement(
+						    m_sQueueSample.m_nFrequency >> 5);
 						if(noise <= 0)
 							m_sQueueSample.m_nFrequency += noise;
 						else
 							m_sQueueSample.m_nFrequency -= noise;
 					}
-					m_sQueueSample.field_16 += 20;
+					m_sQueueSample.m_nReleasingVolumeModificator += 20;
 					m_sQueueSample.m_vecPos = m_avecReflectionsPos[i];
 					AddSampleToRequestedQueue();
 				}
@@ -377,46 +458,51 @@ cAudioManager::AddReflectionsToRequestedQueue()
 void
 cAudioManager::AddReleasingSounds()
 {
-	bool toProcess[44];
+	bool toProcess[44]; // why not 27?
 
 	int8 queue = m_bActiveSampleQueue == 0;
 
 	for(int32 i = 0; i < m_bSampleRequestQueuesStatus[queue]; i++) {
 		tSound &sample = m_asSamples[queue][m_abSampleQueueIndexTable[queue][i]];
-		if (sample.m_bLoopEnded) continue;
+		if(sample.m_bLoopEnded) continue;
 
 		toProcess[i] = false;
 		for(int32 j = 0; j < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; j++) {
 			if(sample.m_nEntityIndex ==
-				    m_asSamples[m_bActiveSampleQueue]
-				                [m_abSampleQueueIndexTable[m_bActiveSampleQueue][j]]
-				                    .m_nEntityIndex &&
-				sample.m_counter == m_asSamples[m_bActiveSampleQueue]
-				                                [m_abSampleQueueIndexTable[m_bActiveSampleQueue][j]]
-				                                    .m_counter) {
+			       m_asSamples[m_bActiveSampleQueue]
+			                  [m_abSampleQueueIndexTable[m_bActiveSampleQueue][j]]
+			                      .m_nEntityIndex &&
+			   sample.m_nCounter ==
+			       m_asSamples[m_bActiveSampleQueue]
+			                  [m_abSampleQueueIndexTable[m_bActiveSampleQueue][j]]
+			                      .m_nCounter) {
 				toProcess[i] = true;
 				break;
 			}
 		}
 		if(!toProcess[i]) {
-			if(sample.m_counter <= 255 || !sample.m_bLoopsRemaining) {
-				if(!sample.field_76) continue;
+			if(sample.m_nCounter <= 255 || !sample.m_bLoopsRemaining) {
+				if(!sample.m_nReleasingVolumeDivider) continue;
 				if(!sample.m_nLoopCount) {
-					if(sample.field_88 == -1) {
-						sample.field_88 = sample.m_bVolume / sample.field_76;
-						if(sample.field_88 <= 0) sample.field_88 = 1;
+					if(sample.m_nVolumeChange == -1) {
+						sample.m_nVolumeChange =
+						    sample.m_bVolume /
+						    sample.m_nReleasingVolumeDivider;
+						if(sample.m_nVolumeChange <= 0)
+							sample.m_nVolumeChange = 1;
 					}
-					if(sample.m_bVolume <= sample.field_88) {
-						sample.field_76 = 0;
+					if(sample.m_bVolume <= sample.m_nVolumeChange) {
+						sample.m_nReleasingVolumeDivider = 0;
 						continue;
 					}
-					sample.m_bVolume -= sample.field_88;
+					sample.m_bVolume -= sample.m_nVolumeChange;
 				}
-				--sample.field_76;
-				if(field_2) {
-					if(sample.field_16 < 20) ++sample.field_16;
+				--sample.m_nReleasingVolumeDivider;
+				if(m_bFifthFrameFlag) {
+					if(sample.m_nReleasingVolumeModificator < 20)
+						++sample.m_nReleasingVolumeModificator;
 				}
-				sample.field_56 = 0;
+				sample.m_bReleasingSoundFlag = 0;
 			}
 			memcpy(&m_sQueueSample, &sample, sizeof(tSound));
 			AddSampleToRequestedQueue();
@@ -432,17 +518,21 @@ cAudioManager::AddSampleToRequestedQueue()
 	bool bReflections;
 
 	if(m_sQueueSample.m_nSampleIndex < TOTAL_AUDIO_SAMPLES) {
-		calculatedVolume = m_sQueueSample.field_16 * (maxVolume - m_sQueueSample.m_bVolume);
+		calculatedVolume = m_sQueueSample.m_nReleasingVolumeModificator *
+		                   (maxVolume - m_sQueueSample.m_bVolume);
 		sampleIndex = m_bSampleRequestQueuesStatus[m_bActiveSampleQueue];
 		if(sampleIndex >= m_bActiveSamples) {
-			sampleIndex = m_abSampleQueueIndexTable[m_bActiveSampleQueue][m_bActiveSamples - 1];
-			if(m_asSamples[m_bActiveSampleQueue][sampleIndex].calculatedVolume <= calculatedVolume) return;
+			sampleIndex =
+			    m_abSampleQueueIndexTable[m_bActiveSampleQueue][m_bActiveSamples - 1];
+			if(m_asSamples[m_bActiveSampleQueue][sampleIndex].m_nCalculatedVolume <=
+			   calculatedVolume)
+				return;
 		} else {
 			++m_bSampleRequestQueuesStatus[m_bActiveSampleQueue];
 		}
-		m_sQueueSample.calculatedVolume = calculatedVolume;
-		m_sQueueSample.m_bLoopEnded = 0;
-		if(m_sQueueSample.m_bIsDistant) {
+		m_sQueueSample.m_nCalculatedVolume = calculatedVolume;
+		m_sQueueSample.m_bLoopEnded = false;
+		if(m_sQueueSample.m_bIs2D) {
 			m_sQueueSample.m_bRequireReflection = false;
 			m_sQueueSample.m_bLoopsRemaining = 0;
 		}
@@ -483,27 +573,27 @@ cAudioManager::ClearActiveSamples()
 {
 	for(int32 i = 0; i < m_bActiveSamples; i++) {
 		m_asActiveSamples[i].m_nEntityIndex = AEHANDLE_NONE;
-		m_asActiveSamples[i].m_counter = 0;
+		m_asActiveSamples[i].m_nCounter = 0;
 		m_asActiveSamples[i].m_nSampleIndex = NO_SAMPLE;
 		m_asActiveSamples[i].m_bBankIndex = SAMPLEBANK_INVALID;
-		m_asActiveSamples[i].m_bIsDistant = false;
-		m_asActiveSamples[i].field_16 = 5;
+		m_asActiveSamples[i].m_bIs2D = false;
+		m_asActiveSamples[i].m_nReleasingVolumeModificator = 5;
 		m_asActiveSamples[i].m_nFrequency = 0;
 		m_asActiveSamples[i].m_bVolume = 0;
 		m_asActiveSamples[i].m_bEmittingVolume = 0;
 		m_asActiveSamples[i].m_fDistance = 0.0f;
-		m_asActiveSamples[i].m_bIsProcessed = 0;
-		m_asActiveSamples[i].m_bLoopEnded = 0;
+		m_asActiveSamples[i].m_bIsProcessed = false;
+		m_asActiveSamples[i].m_bLoopEnded = false;
 		m_asActiveSamples[i].m_nLoopCount = 1;
 		m_asActiveSamples[i].m_nLoopStart = 0;
 		m_asActiveSamples[i].m_nLoopEnd = -1;
-		m_asActiveSamples[i].field_48 = 0.0f;
+		m_asActiveSamples[i].m_fSpeedMultiplier = 0.0f;
 		m_asActiveSamples[i].m_fSoundIntensity = 200.0f;
 		m_asActiveSamples[i].m_bOffset = 63;
-		m_asActiveSamples[i].field_56 = 0;
-		m_asActiveSamples[i].calculatedVolume = 0;
-		m_asActiveSamples[i].field_76 = 0;
-		m_asActiveSamples[i].field_88 = -1;
+		m_asActiveSamples[i].m_bReleasingSoundFlag = 0;
+		m_asActiveSamples[i].m_nCalculatedVolume = 0;
+		m_asActiveSamples[i].m_nReleasingVolumeDivider = 0;
+		m_asActiveSamples[i].m_nVolumeChange = -1;
 		m_asActiveSamples[i].m_vecPos = {0.0f, 0.0f, 0.0f};
 		m_asActiveSamples[i].m_bReverbFlag = false;
 		m_asActiveSamples[i].m_bLoopsRemaining = 0;
@@ -516,12 +606,12 @@ cAudioManager::ClearMissionAudio()
 {
 	if(m_bIsInitialised) {
 		m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
-		m_sMissionAudio.m_bLoadingStatus = 0;
-		m_sMissionAudio.m_bPlayStatus = 0;
+		m_sMissionAudio.m_bLoadingStatus = LOADING_STATUS_NOT_LOADED;
+		m_sMissionAudio.m_bPlayStatus = PLAY_STATUS_STOPPED;
 		m_sMissionAudio.field_22 = 0;
 		m_sMissionAudio.m_bIsPlayed = false;
-		m_sMissionAudio.field_12 = 1;
-		m_sMissionAudio.field_24 = 0;
+		m_sMissionAudio.m_bPredefinedProperties = 1;
+		m_sMissionAudio.m_nMissionAudioCounter = 0;
 	}
 }
 
@@ -542,14 +632,15 @@ cAudioManager::ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1,
 	if(!TheCamera.Get_Just_Switched_Status() && speedMultiplier != 0.0f) {
 		float dist = position2 - position1;
 		if(dist != 0.0f) {
-			float speedOfSource = (dist / field_19195) * speedMultiplier;
-			if(speedOfSound > Abs(speedOfSource)) {
+			float speedOfSource = (dist / m_bTimeSpent) * speedMultiplier;
+			if(m_fSpeedOfSound > Abs(speedOfSource)) {
 				if(speedOfSource < 0.0f) {
 					speedOfSource = max(speedOfSource, -1.5f);
 				} else {
 					speedOfSource = min(speedOfSource, 1.5f);
 				}
-				newFreq = (oldFreq * speedOfSound) / (speedOfSource + speedOfSound);
+				newFreq =
+				    (oldFreq * m_fSpeedOfSound) / (speedOfSource + m_fSpeedOfSound);
 			}
 		}
 	}
@@ -573,7 +664,9 @@ cAudioManager::ComputeVolume(uint8 emittingVolume, float soundIntensity, float d
 	if((soundIntensity * 0.2f) <= distance) {
 		newSoundIntensity = soundIntensity * 0.2f;
 		emittingVolume =
-		    sq((soundIntensity - newSoundIntensity - (distance - newSoundIntensity)) / (soundIntensity - newSoundIntensity)) * emittingVolume;
+		    sq((soundIntensity - newSoundIntensity - (distance - newSoundIntensity)) /
+		       (soundIntensity - newSoundIntensity)) *
+		    emittingVolume;
 	}
 	return emittingVolume;
 }
@@ -618,7 +711,8 @@ cAudioManager::DestroyAllGameCreatedEntities()
 				case AUDIOTYPE_GARAGE:
 				case AUDIOTYPE_FIREHYDRANT: DestroyEntity(i); break;
 				case AUDIOTYPE_SCRIPTOBJECT:
-					entity = (cAudioScriptObject *)m_asAudioEntities[i].m_pEntity;
+					entity =
+					    (cAudioScriptObject *)m_asAudioEntities[i].m_pEntity;
 					if(entity) {
 						delete entity;
 						m_asAudioEntities[i].m_pEntity = nil;
@@ -629,21 +723,25 @@ cAudioManager::DestroyAllGameCreatedEntities()
 				}
 			}
 		}
-		m_nScriptObjectEntityTotal = 0;
+		m_sAudioScriptObjectManager.m_nScriptObjectEntityTotal = 0;
 	}
 }
 
 void
 cAudioManager::DestroyEntity(int32 id)
 {
-	if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots && m_asAudioEntities[id].m_bIsUsed) {
+	if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots &&
+	   m_asAudioEntities[id].m_bIsUsed) {
 		m_asAudioEntities[id].m_bIsUsed = false;
 		for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) {
 			if(id == m_anAudioEntityIndices[i]) {
 				if(i < totalAudioEntitiesSlots - 1)
-					memmove(&m_anAudioEntityIndices[i], &m_anAudioEntityIndices[i + 1],
-					        4 * (m_nAudioEntitiesTotal - (i + 1)));
-				m_anAudioEntityIndices[--m_nAudioEntitiesTotal] = totalAudioEntitiesSlots;
+					memmove(&m_anAudioEntityIndices[i],
+					        &m_anAudioEntityIndices[i + 1],
+					        NUM_AUDIOENTITY_EVENTS *
+					            (m_nAudioEntitiesTotal - (i + 1)));
+				m_anAudioEntityIndices[--m_nAudioEntitiesTotal] =
+				    totalAudioEntitiesSlots;
 				return;
 			}
 		}
@@ -653,7 +751,8 @@ cAudioManager::DestroyEntity(int32 id)
 void
 cAudioManager::DoJumboVolOffset() const
 {
-	if(!(m_FrameCounter % (m_anRandomTable[0] % 6 + 3))) jumboVolOffset = m_anRandomTable[1] % 60;
+	if(!(m_FrameCounter % (m_anRandomTable[0] % 6 + 3)))
+		gJumboVolOffsetPercentage = m_anRandomTable[1] % 60;
 }
 
 uint32
@@ -684,11 +783,14 @@ cAudioManager::GetCopTalkSfx(int16 sound)
 		if(sound != SOUND_PED_PURSUIT_COP) { return GetGenericMaleTalkSfx(sound); }
 
 		pedState = FindPlayerPed()->m_nPedState;
-		if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE;
+		if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE)
+			return NO_SAMPLE;
 		GetPhrase(&sfx, &lastSfx, SFX_COP_VOICE_1_CHASE_1, 7);
 	}
 
-	return (SFX_COP_VOICE_2_ARREST_1 - SFX_COP_VOICE_1_ARREST_1) * (m_sQueueSample.m_nEntityIndex % 5) + sfx;
+	return (SFX_COP_VOICE_2_ARREST_1 - SFX_COP_VOICE_1_ARREST_1) *
+	           (m_sQueueSample.m_nEntityIndex % 5) +
+	       sfx;
 }
 
 uint32
@@ -704,11 +806,14 @@ cAudioManager::GetSwatTalkSfx(int16 sound)
 		if(sound != SOUND_PED_PURSUIT_SWAT) { return GetGenericMaleTalkSfx(sound); }
 
 		pedState = FindPlayerPed()->m_nPedState;
-		if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE;
+		if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE)
+			return NO_SAMPLE;
 		GetPhrase(&sfx, &lastSfx, SFX_SWAT_VOICE_1_CHASE_1, 6);
 	}
 
-	return (SFX_SWAT_VOICE_2_CHASE_1 - SFX_SWAT_VOICE_1_CHASE_1) * (m_sQueueSample.m_nEntityIndex % 3) + sfx;
+	return (SFX_SWAT_VOICE_2_CHASE_1 - SFX_SWAT_VOICE_1_CHASE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 4) +
+	       sfx;
 }
 
 uint32
@@ -724,11 +829,14 @@ cAudioManager::GetFBITalkSfx(int16 sound)
 		if(sound != SOUND_PED_PURSUIT_FBI) { return GetGenericMaleTalkSfx(sound); }
 
 		pedState = FindPlayerPed()->m_nPedState;
-		if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE;
+		if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE)
+			return NO_SAMPLE;
 		GetPhrase(&sfx, &lastSfx, SFX_FBI_VOICE_1_CHASE_1, 6);
 	}
 
-	return (SFX_FBI_VOICE_2_CHASE_1 - SFX_FBI_VOICE_1_CHASE_1) * (m_sQueueSample.m_nEntityIndex % 3) + sfx;
+	return (SFX_FBI_VOICE_2_CHASE_1 - SFX_FBI_VOICE_1_CHASE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 3) +
+	       sfx;
 }
 
 uint32
@@ -741,10 +849,13 @@ cAudioManager::GetArmyTalkSfx(int16 sound)
 	if(sound != SOUND_PED_PURSUIT_ARMY) { return GetGenericMaleTalkSfx(sound); }
 
 	pedState = FindPlayerPed()->m_nPedState;
-	if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE;
+	if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE)
+		return NO_SAMPLE;
 	GetPhrase(&sfx, &lastSfx, SFX_ARMY_VOICE_1_CHASE_1, 15);
 
-	return (SFX_ARMY_VOICE_2_CHASE_1 - SFX_ARMY_VOICE_1_CHASE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_ARMY_VOICE_2_CHASE_1 - SFX_ARMY_VOICE_1_CHASE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -754,14 +865,24 @@ cAudioManager::GetMedicTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_GUN_PANIC_1, 5); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_CARJACKED_1, 5); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_GUN_PANIC_1, 5);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_CARJACKED_1, 5);
+		break;
 	case SOUND_PED_HEALING: GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_AT_VICTIM_1, 12); break;
-	case SOUND_PED_LEAVE_VEHICLE: GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_GET_OUT_VAN_CHAT_1, 9); break;
-	case SOUND_PED_FLEE_RUN: GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_RUN_FROM_FIGHT_1, 6); break;
+	case SOUND_PED_LEAVE_VEHICLE:
+		GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_GET_OUT_VAN_CHAT_1, 9);
+		break;
+	case SOUND_PED_FLEE_RUN:
+		GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_RUN_FROM_FIGHT_1, 6);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
-	return (SFX_MEDIC_VOICE_2_GUN_PANIC_1 - SFX_MEDIC_VOICE_1_GUN_PANIC_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_MEDIC_VOICE_2_GUN_PANIC_1 - SFX_MEDIC_VOICE_1_GUN_PANIC_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -777,10 +898,14 @@ cAudioManager::GetNormalMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_GUN_PANIC_1, 7); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_GUN_PANIC_1, 7);
+		break;
 	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_CARJACKED_1, 7); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_DODGE_1, 9); break;
-	case SOUND_PED_FLEE_RUN: GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_RUN_FROM_FIGHT_1, 5); break;
+	case SOUND_PED_FLEE_RUN:
+		GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_RUN_FROM_FIGHT_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_DRIVER_ABUSE_1, 12);
 		break;
@@ -804,7 +929,10 @@ cAudioManager::GetTaxiDriverTalkSfx(int16 sound)
 		if(sound != SOUND_PED_CAR_COLLISION) return GetGenericMaleTalkSfx(sound);
 		GetPhrase(&sfx, &lastSfx, SFX_ASIAN_TAXI_DRIVER_VOICE_1_DRIVER_ABUSE_1, 6);
 	}
-	return (SFX_ASIAN_TAXI_DRIVER_VOICE_2_DRIVER_ABUSE_1 - SFX_ASIAN_TAXI_DRIVER_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_ASIAN_TAXI_DRIVER_VOICE_2_DRIVER_ABUSE_1 -
+	        SFX_ASIAN_TAXI_DRIVER_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -833,16 +961,26 @@ cAudioManager::GetMafiaTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKING: GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKING_1, 2); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKED_1, 2); break;
+	case SOUND_PED_CAR_JACKING:
+		GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKING_1, 2);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKED_1, 2);
+		break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_FIGHT_1, 5); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_DODGE_1, 5); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_EYING_1, 3); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
+		break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_EYING_1, 3);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CHAT_1, 7); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
-	return (SFX_MAFIA_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_MAFIA_MALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 3) + sfx;
+	return (SFX_MAFIA_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_MAFIA_MALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 3) +
+	       sfx;
 }
 
 uint32
@@ -852,13 +990,23 @@ cAudioManager::GetTriadTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_GUN_COOL_1, 3); break;
-	case SOUND_PED_CAR_JACKING: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKING_1, 2); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKED_1, 2); break;
+	case SOUND_PED_HANDS_UP:
+		GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_GUN_COOL_1, 3);
+		break;
+	case SOUND_PED_CAR_JACKING:
+		GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKING_1, 2);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKED_1, 2);
+		break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_FIGHT_1, 5); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_DODGE_1, 4); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_DRIVER_ABUSE_1, 7); break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_EYING_1, 3); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_DRIVER_ABUSE_1, 7);
+		break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_EYING_1, 3);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CHAT_1, 8); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
@@ -872,21 +1020,33 @@ cAudioManager::GetDiabloTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_GUN_COOL_1, 4); break;
+	case SOUND_PED_HANDS_UP:
+		GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_GUN_COOL_1, 4);
+		break;
 	case SOUND_PED_HANDS_COWER:
 		sound = SOUND_PED_FLEE_SPRINT;
 		return GetGenericMaleTalkSfx(sound);
 		break;
-	case SOUND_PED_CAR_JACKING: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKING_1, 2); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKED_1, 2); break;
+	case SOUND_PED_CAR_JACKING:
+		GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKING_1, 2);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKED_1, 2);
+		break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_FIGHT_1, 4); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_DODGE_1, 4); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_DRIVER_ABUSE_1, 5); break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_EYING_1, 4); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_DRIVER_ABUSE_1, 5);
+		break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_EYING_1, 4);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CHAT_1, 5); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
-	return (SFX_DIABLO_MALE_VOICE_2_CHAT_1 - SFX_DIABLO_MALE_VOICE_1_CHAT_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_DIABLO_MALE_VOICE_2_CHAT_1 - SFX_DIABLO_MALE_VOICE_1_CHAT_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -896,15 +1056,23 @@ cAudioManager::GetYakuzaTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKING: GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKING_1, 2); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKED_1, 2); break;
+	case SOUND_PED_CAR_JACKING:
+		GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKING_1, 2);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKED_1, 2);
+		break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_FIGHT_1, 5); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_DODGE_1, 4); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CHAT_1, 5); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
-	return (SFX_YAKUZA_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_YAKUZA_MALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_YAKUZA_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_YAKUZA_MALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -915,16 +1083,24 @@ cAudioManager::GetYardieTalkSfx(int16 sound)
 
 	switch(sound) {
 	case SOUND_PED_HANDS_UP: sfx = SFX_YARDIE_MALE_VOICE_1_GUN_COOL_1; break;
-	case SOUND_PED_CAR_JACKING: GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_CARJACKING_1, 2); break;
+	case SOUND_PED_CAR_JACKING:
+		GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_CARJACKING_1, 2);
+		break;
 	case SOUND_PED_CAR_JACKED: sfx = SFX_YARDIE_MALE_VOICE_1_CARJACKED_1; break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_FIGHT_1, 6); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_DODGE_1, 5); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_EYING_1, 2); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
+		break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_EYING_1, 2);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_CHAT_1, 8); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
-	return (SFX_YARDIE_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_YARDIE_MALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_YARDIE_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_YARDIE_MALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -934,16 +1110,31 @@ cAudioManager::GetColumbianTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKING: GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKING_1, 2); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKED_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_FIGHT_1, 5); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DODGE_1, 5); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_EYING_1, 2); break;
+	case SOUND_PED_CAR_JACKING:
+		GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKING_1, 2);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKED_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_FIGHT_1, 5);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DODGE_1, 5);
+		break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
+		break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_EYING_1, 2);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CHAT_1, 5); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
-	return (SFX_COLUMBIAN_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_COLUMBIAN_MALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_COLUMBIAN_MALE_VOICE_2_DRIVER_ABUSE_1 -
+	        SFX_COLUMBIAN_MALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -953,18 +1144,30 @@ cAudioManager::GetHoodTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_GUN_COOL_1, 5); break;
-	case SOUND_PED_CAR_JACKING: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKING_1, 2); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKED_1, 2); break;
+	case SOUND_PED_HANDS_UP:
+		GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_GUN_COOL_1, 5);
+		break;
+	case SOUND_PED_CAR_JACKING:
+		GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKING_1, 2);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKED_1, 2);
+		break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_FIGHT_1, 6); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_DODGE_1, 5); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_DRIVER_ABUSE_1, 7); break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_EYING_1, 2); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_DRIVER_ABUSE_1, 7);
+		break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_EYING_1, 2);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CHAT_1, 6); break;
 
 	default: return GetGenericMaleTalkSfx(sound); break;
 	}
-	return (SFX_HOOD_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_HOOD_MALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_HOOD_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_HOOD_MALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -974,11 +1177,19 @@ cAudioManager::GetBlackCriminalTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_GUN_COOL_1, 4); break;
+	case SOUND_PED_HANDS_UP:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_GUN_COOL_1, 4);
+		break;
 	case SOUND_PED_CAR_JACKING: sfx = SFX_BLACK_CRIMINAL_VOICE_1_CARJACKING_1; break;
-	case SOUND_PED_MUGGING: GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_MUGGING_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_FIGHT_1, 5); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_DODGE_1, 6); break;
+	case SOUND_PED_MUGGING:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_MUGGING_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_FIGHT_1, 5);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_DODGE_1, 6);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
@@ -994,11 +1205,19 @@ cAudioManager::GetWhiteCriminalTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_GUN_COOL_1, 3); break;
+	case SOUND_PED_HANDS_UP:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_GUN_COOL_1, 3);
+		break;
 	case SOUND_PED_CAR_JACKING: sfx = SFX_WHITE_CRIMINAL_VOICE_1_CARJACKING_1; break;
-	case SOUND_PED_MUGGING: GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_MUGGING_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_FIGHT_1, 4); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_MUGGING:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_MUGGING_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_FIGHT_1, 4);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
@@ -1014,13 +1233,27 @@ cAudioManager::GetMaleNo2TalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CARJACKED_1, 3); break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_MUGGED_1, 4); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_FIGHT_1, 4); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DODGE_1, 4); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 7); break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_EYING_1, 5); break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CARJACKED_1, 3);
+		break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_MUGGED_1, 4);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_FIGHT_1, 4);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DODGE_1, 4);
+		break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 7);
+		break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_EYING_1, 5);
+		break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1033,13 +1266,21 @@ cAudioManager::GetBlackProjectMaleTalkSfx(int16 sound, int32 model)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_GUN_COOL_1, 3); break;
+	case SOUND_PED_HANDS_UP:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_GUN_COOL_1, 3);
+		break;
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_FIGHT_1, 6); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_FIGHT_1, 6);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_DRIVER_ABUSE_1, 7);
 		break;
@@ -1050,7 +1291,9 @@ cAudioManager::GetBlackProjectMaleTalkSfx(int16 sound, int32 model)
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 
-	if(model == MI_P_MAN2) sfx += (SFX_BLACK_PROJECT_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_BLACK_PROJECT_MALE_VOICE_1_DRIVER_ABUSE_1);
+	if(model == MI_P_MAN2)
+		sfx += (SFX_BLACK_PROJECT_MALE_VOICE_2_DRIVER_ABUSE_1 -
+		        SFX_BLACK_PROJECT_MALE_VOICE_1_DRIVER_ABUSE_1);
 	return sfx;
 }
 
@@ -1061,9 +1304,15 @@ cAudioManager::GetWhiteFatMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_CARJACKED_1, 3); break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_MUGGED_1, 3); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_DODGE_1, 9); break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_CARJACKED_1, 3);
+		break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_MUGGED_1, 3);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_DODGE_1, 9);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_DRIVER_ABUSE_1, 9);
 		break;
@@ -1083,9 +1332,15 @@ cAudioManager::GetBlackFatMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_CARJACKED_1, 4); break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_MUGGED_1, 3); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_DODGE_1, 7); break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_CARJACKED_1, 4);
+		break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_MUGGED_1, 3);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_DODGE_1, 7);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
@@ -1142,7 +1397,9 @@ cAudioManager::GetWhiteCasualFemaleTalkSfx(int16 sound)
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_CARJACKED_1, 2);
 		break;
 	case SOUND_PED_ROBBED: sfx = SFX_WHITE_CASUAL_FEMALE_VOICE_1_MUGGED_1; break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_DODGE_1, 3); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_DODGE_1, 3);
+		break;
 	case SOUND_PED_FLEE_RUN:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 2);
 		break;
@@ -1152,7 +1409,9 @@ cAudioManager::GetWhiteCasualFemaleTalkSfx(int16 sound)
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_SHOCKED_1, 2);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_CHAT_1, 4); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_CHAT_1, 4);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1165,15 +1424,23 @@ cAudioManager::GetFemaleNo3TalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_GUN_PANIC_1, 5); break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_CARJACKED_1, 3); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_GUN_PANIC_1, 5);
+		break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_CARJACKED_1, 3);
+		break;
 	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_MUGGED_1, 3); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_DODGE_1, 6); break;
-	case SOUND_PED_FLEE_RUN: GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_RUN_FROM_FIGHT_1, 4); break;
+	case SOUND_PED_FLEE_RUN:
+		GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_RUN_FROM_FIGHT_1, 4);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
-	case SOUND_PED_CHAT_EVENT: GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_SHOCKED_1, 4); break;
+	case SOUND_PED_CHAT_EVENT:
+		GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_SHOCKED_1, 4);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_CHAT_1, 5); break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
@@ -1193,15 +1460,21 @@ cAudioManager::GetBlackFatFemaleTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_SHOCKED_1, 5);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1217,8 +1490,12 @@ cAudioManager::GetWhiteFatFemaleTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_DODGE_1, 6); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_DODGE_1, 6);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 8);
 		break;
@@ -1228,7 +1505,9 @@ cAudioManager::GetWhiteFatFemaleTalkSfx(int16 sound)
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_SHOCKED_1, 4);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_CHAT_1, 8); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_CHAT_1, 8);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1248,17 +1527,23 @@ cAudioManager::GetBlackFemaleProstituteTalkSfx(int16 sound)
 	case SOUND_PED_ATTACK:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_FIGHT_1, 4);
 		break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_DODGE_1, 3); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_DODGE_1, 3);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
 	case SOUND_PED_SOLICIT:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_SOLICIT_1, 8);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_CHAT_1, 4); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_CHAT_1, 4);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
-	return (SFX_BLACK_PROSTITUTE_VOICE_2_CHAT_1 - SFX_BLACK_PROSTITUTE_VOICE_1_CHAT_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_BLACK_PROSTITUTE_VOICE_2_CHAT_1 - SFX_BLACK_PROSTITUTE_VOICE_1_CHAT_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -1274,17 +1559,23 @@ cAudioManager::GetWhiteFemaleProstituteTalkSfx(int16 sound)
 	case SOUND_PED_ATTACK:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_FIGHT_1, 4);
 		break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_DODGE_1, 3); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_DODGE_1, 3);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
 	case SOUND_PED_SOLICIT:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_SOLICIT_1, 8);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_CHAT_1, 4); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_CHAT_1, 4);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
-	return (SFX_WHITE_PROSTITUTE_VOICE_2_CHAT_1 - SFX_WHITE_PROSTITUTE_VOICE_1_CHAT_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_WHITE_PROSTITUTE_VOICE_2_CHAT_1 - SFX_WHITE_PROSTITUTE_VOICE_1_CHAT_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -1312,7 +1603,9 @@ cAudioManager::GetBlackProjectFemaleOldTalkSfx(int16 sound)
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_SHOCKED_1, 2);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_CHAT_1, 10); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_CHAT_1, 10);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1341,7 +1634,9 @@ cAudioManager::GetBlackProjectFemaleYoungTalkSfx(int16 sound)
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_SHOCKED_1, 5);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1360,13 +1655,21 @@ cAudioManager::GetChinatownMaleOldTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_FIGHT_1, 5); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_DODGE_1, 6); break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_FIGHT_1, 5);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_DODGE_1, 6);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_EYING_1, 3); break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_EYING_1, 3);
+		break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1385,15 +1688,21 @@ cAudioManager::GetChinatownMaleYoungTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_FIGHT_1, 6); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_FIGHT_1, 6);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
 	case SOUND_PED_CHAT_SEXY:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_EYING_1, 3);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1409,13 +1718,19 @@ cAudioManager::GetChinatownFemaleOldTalkSfx(int16 sound)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_GUN_PANIC_1, 3);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
 	case SOUND_PED_CHAT_EVENT: sfx = SFX_CHINATOWN_OLD_FEMALE_VOICE_1_SHOCKED_1; break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1431,15 +1746,21 @@ cAudioManager::GetChinatownFemaleYoungTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_DODGE_1, 6); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_DODGE_1, 6);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7);
 		break;
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_SHOCKED_1, 4);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1458,16 +1779,27 @@ cAudioManager::GetLittleItalyMaleTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_FIGHT_1, 5); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_FIGHT_1, 5);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_DRIVER_ABUSE_1, 7);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
-	return (SFX_LITTLE_ITALY_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_LITTLE_ITALY_MALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_LITTLE_ITALY_MALE_VOICE_2_DRIVER_ABUSE_1 -
+	        SFX_LITTLE_ITALY_MALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -1480,15 +1812,21 @@ cAudioManager::GetLittleItalyFemaleOldTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_DODGE_1, 6); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_DODGE_1, 6);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7);
 		break;
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_SHOCKED_1, 4);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1507,14 +1845,18 @@ cAudioManager::GetLittleItalyFemaleYoungTalkSfx(int16 sound)
 	case SOUND_PED_ROBBED:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_MUGGED_1, 2);
 		break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_DODGE_1, 7); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_DODGE_1, 7);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_SHOCKED_1, 4);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1530,13 +1872,21 @@ cAudioManager::GetWhiteDockerMaleTalkSfx(int16 sound)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_GUN_PANIC_1, 2);
 		break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_FIGHT_1, 3); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_DODGE_1, 4); break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_FIGHT_1, 3);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_DODGE_1, 4);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_EYING_1, 3); break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_CHAT_1, 5); break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_EYING_1, 3);
+		break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_CHAT_1, 5);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1552,12 +1902,16 @@ cAudioManager::GetBlackDockerMaleTalkSfx(int16 sound)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_GUN_PANIC_1, 3);
 		break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_FIGHT_1, 5); break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_FIGHT_1, 5);
+		break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_DODGE_1, 5); break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_EYING_1, 3); break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_EYING_1, 3);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_CHAT_1, 5); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
@@ -1571,15 +1925,21 @@ cAudioManager::GetScumMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_GUN_PANIC_1, 5); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_GUN_PANIC_1, 5);
+		break;
 	case SOUND_PED_ROBBED: sfx = SFX_SCUM_MALE_VOICE_1_MUGGED_1; break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_FIGHT_1, 0xA); break;
+	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_FIGHT_1, 10); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_DODGE_1, 5); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
+		break;
 	case SOUND_PED_WAIT_DOUBLEBACK:
 		GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_LOST_1, 3);
 		break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_EYING_1, 5); break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_EYING_1, 5);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_CHAT_1, 9); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
@@ -1593,8 +1953,12 @@ cAudioManager::GetScumFemaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_GUN_PANIC_1, 4); break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_MUGGED_1, 2); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_GUN_PANIC_1, 4);
+		break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_FIGHT_1, 4); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_DODGE_1, 8); break;
 	case SOUND_PED_CAR_COLLISION:
@@ -1616,13 +1980,21 @@ cAudioManager::GetWhiteWorkerMaleTalkSfx(int16 sound)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_GUN_PANIC_1, 3);
 		break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_FIGHT_1, 3); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_DODGE_1, 4); break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_FIGHT_1, 3);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_DODGE_1, 4);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_EYING_1, 2); break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_EYING_1, 2);
+		break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1638,13 +2010,21 @@ cAudioManager::GetBlackWorkerMaleTalkSfx(int16 sound)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_GUN_PANIC_1, 4);
 		break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_FIGHT_1, 3); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_DODGE_1, 3); break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_FIGHT_1, 3);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_DODGE_1, 3);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_EYING_1, 3); break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_CHAT_1, 4); break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_EYING_1, 3);
+		break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_CHAT_1, 4);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1663,20 +2043,30 @@ cAudioManager::GetBusinessMaleYoungTalkSfx(int16 sound, int32 model)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_FIGHT_1, 4); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_DODGE_1, 4); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_FIGHT_1, 4);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_DODGE_1, 4);
+		break;
 	case SOUND_PED_FLEE_RUN:
 		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_RUN_FROM_FIGHT_1, 5);
 		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 
-	if(model == MI_B_MAN3) sfx += (SFX_BUSINESS_MALE_YOUNG_VOICE_2_DRIVER_ABUSE_1 - SFX_BUSINESS_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1);
+	if(model == MI_B_MAN3)
+		sfx += (SFX_BUSINESS_MALE_YOUNG_VOICE_2_DRIVER_ABUSE_1 -
+		        SFX_BUSINESS_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1);
 	return sfx;
 }
 
@@ -1693,14 +2083,24 @@ cAudioManager::GetBusinessMaleOldTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_CARJACKED_1, 2);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_FIGHT_1, 5); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_DODGE_1, 4); break;
-	case SOUND_PED_FLEE_RUN: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MRUN_FROM_FIGHT_1, 5); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_FIGHT_1, 5);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_DODGE_1, 4);
+		break;
+	case SOUND_PED_FLEE_RUN:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MRUN_FROM_FIGHT_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_CHAT_1, 5); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_CHAT_1, 5);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1716,19 +2116,33 @@ cAudioManager::GetWhiteBusinessFemaleTalkSfx(int16 sound, int32 model)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_GUN_PANIC_1, 4);
 		break;
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CARJACKED_1, 2); break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6); break;
-	case SOUND_PED_FLEE_RUN: GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 4); break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CARJACKED_1, 2);
+		break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6);
+		break;
+	case SOUND_PED_FLEE_RUN:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 4);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
-	case SOUND_PED_CHAT_EVENT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_SHOCKED_1, 4); break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT_EVENT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_SHOCKED_1, 4);
+		break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 
-	if(model == MI_B_WOM2) sfx += (SFX_WHITE_BUSINESS_FEMALE_VOICE_2_DRIVER_ABUSE_1 - SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DRIVER_ABUSE_1);
+	if(model == MI_B_WOM2)
+		sfx += (SFX_WHITE_BUSINESS_FEMALE_VOICE_2_DRIVER_ABUSE_1 -
+		        SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DRIVER_ABUSE_1);
 	return sfx;
 }
 
@@ -1745,8 +2159,12 @@ cAudioManager::GetBlackBusinessFemaleTalkSfx(int16 sound)
 	case SOUND_PED_CAR_JACKED:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_CARAJACKED_1, 4);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 3); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 3);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6);
+		break;
 	case SOUND_PED_FLEE_RUN:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 6);
 		break;
@@ -1756,7 +2174,9 @@ cAudioManager::GetBlackBusinessFemaleTalkSfx(int16 sound)
 	case SOUND_PED_CHAT_EVENT:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_SHOCKED_1, 4);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1769,14 +2189,18 @@ cAudioManager::GetSupermodelMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_CARJACKED_1, 2); break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_CARJACKED_1, 2);
+		break;
 	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_MUGGED_1, 2); break;
 	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_FIGHT_1, 5); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_DODGE_1, 6); break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
-	case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_EYING_1, 3); break;
+	case SOUND_PED_CHAT_SEXY:
+		GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_EYING_1, 3);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_CHAT_1, 6); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
@@ -1793,7 +2217,9 @@ cAudioManager::GetSupermodelFemaleTalkSfx(int16 sound)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_GUN_PANIC_1, 4);
 		break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_MUGGED_1, 3); break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_MUGGED_1, 3);
+		break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_DODGE_1, 4); break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7);
@@ -1814,8 +2240,12 @@ cAudioManager::GetStewardMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_GUN_PANIC_1, 3); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_FIGHT_1, 4); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_GUN_PANIC_1, 3);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_FIGHT_1, 4);
+		break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_DODGE_1, 3); break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_DRIVER_ABUSE_1, 5);
@@ -1836,14 +2266,19 @@ cAudioManager::GetStewardFemaleTalkSfx(int16 sound)
 	case SOUND_PED_HANDS_COWER:
 		GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_GUN_PANIC_1, 3);
 		break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_CHAT_1, 5); break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
-	return (SFX_STEWARD_FEMALE_VOICE_2_DRIVER_ABUSE_1 - SFX_STEWARD_FEMALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_STEWARD_FEMALE_VOICE_2_DRIVER_ABUSE_1 -
+	        SFX_STEWARD_FEMALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -1853,15 +2288,25 @@ cAudioManager::GetFanMaleTalkSfx(int16 sound, int32 model)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_FIGHT_1, 3); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DODGE_1, 4); break;
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DRIVER_ABUSE_1, 5); break;
-	case SOUND_PED_CHAT_EVENT: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_SHOCKED_1, 2); break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_FIGHT_1, 3);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DODGE_1, 4);
+		break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DRIVER_ABUSE_1, 5);
+		break;
+	case SOUND_PED_CHAT_EVENT:
+		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_SHOCKED_1, 2);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_CHAT_1, 6); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 
-	if(model == MI_FAN_MAN2) sfx += (SFX_FOOTBALL_MALE_VOICE_2_DRIVER_ABUSE_1 - SFX_FOOTBALL_MALE_VOICE_1_DRIVER_ABUSE_1);
+	if(model == MI_FAN_MAN2)
+		sfx += (SFX_FOOTBALL_MALE_VOICE_2_DRIVER_ABUSE_1 -
+		        SFX_FOOTBALL_MALE_VOICE_1_DRIVER_ABUSE_1);
 	return sfx;
 }
 
@@ -1873,15 +2318,24 @@ cAudioManager::GetFanFemaleTalkSfx(int16 sound)
 
 	switch(sound) {
 	case SOUND_PED_ROBBED: sfx = SFX_FOOTBALL_FEMALE_VOICE_1_MUGGED_1; break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_DODGE_1, 4); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_DODGE_1, 4);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
-	case SOUND_PED_CHAT_EVENT: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_SHOCKED_1, 2); break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT_EVENT:
+		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_SHOCKED_1, 2);
+		break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
-	return (SFX_FOOTBALL_FEMALE_VOICE_2_DRIVER_ABUSE_1 - SFX_FOOTBALL_FEMALE_VOICE_1_DRIVER_ABUSE_1) * (m_sQueueSample.m_nEntityIndex % 2) + sfx;
+	return (SFX_FOOTBALL_FEMALE_VOICE_2_DRIVER_ABUSE_1 -
+	        SFX_FOOTBALL_FEMALE_VOICE_1_DRIVER_ABUSE_1) *
+	           (m_sQueueSample.m_nEntityIndex % 2) +
+	       sfx;
 }
 
 uint32
@@ -1891,9 +2345,15 @@ cAudioManager::GetHospitalMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_GUN_PANIC_1, 4); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_FIGHT_1, 4); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_DODGE_1, 4); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_GUN_PANIC_1, 4);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_FIGHT_1, 4);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_DODGE_1, 4);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
@@ -1910,11 +2370,15 @@ cAudioManager::GetHospitalFemaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_CHAT_1, 6); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_CHAT_1, 6);
+		break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1934,14 +2398,18 @@ cAudioManager::GetWhiteConstructionWorkerTalkSfx(int16 sound)
 	case SOUND_PED_ATTACK:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_FIGHT_1, 5);
 		break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
 	case SOUND_PED_CHAT_SEXY:
 		GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_EYING_1, 3);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_CHAT_1, 7); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_CHAT_1, 7);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1963,14 +2431,18 @@ cAudioManager::GetBlackConstructionWorkerTalkSfx(int16 sound)
 	case SOUND_PED_ATTACK:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_FIGHT_1, 5);
 		break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_DODGE_1, 5); break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_DODGE_1, 5);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_DRIVER_ABUSE_1, 5);
 		break;
 	case SOUND_PED_CHAT_SEXY:
 		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_EYING_1, 4);
 		break;
-	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_CHAT_1, 4); break;
+	case SOUND_PED_CHAT:
+		GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_CHAT_1, 4);
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -1983,13 +2455,17 @@ cAudioManager::GetShopperFemaleTalkSfx(int16 sound, int32 model)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_CARJACKED_1, 2); break;
+	case SOUND_PED_CAR_JACKED:
+		GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_CARJACKED_1, 2);
+		break;
 	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_MUGGED_1, 2); break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_DODGE_1, 6); break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_DRIVER_ABUSE_1, 7);
 		break;
-	case SOUND_PED_CHAT_EVENT: GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_SHOCKED_1, 4); break;
+	case SOUND_PED_CHAT_EVENT:
+		GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_SHOCKED_1, 4);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_CHAT_1, 7); break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
@@ -2009,14 +2485,22 @@ cAudioManager::GetStudentMaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_GUN_PANIC_1, 2); break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_FIGHT_1, 4); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_GUN_PANIC_1, 2);
+		break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_FIGHT_1, 4);
+		break;
 	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_DODGE_1, 4); break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
-	case SOUND_PED_CHAT_EVENT: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_SHOCKED_1, 3); break;
+	case SOUND_PED_CHAT_EVENT:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_SHOCKED_1, 3);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_CHAT_1, 5); break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
@@ -2030,14 +2514,24 @@ cAudioManager::GetStudentFemaleTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_COWER: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_GUN_PANIC_1, 4); break;
-	case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_MUGGED_1, 2); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_FIGHT_1, 4); break;
-	case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_DODGE_1, 4); break;
+	case SOUND_PED_HANDS_COWER:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_GUN_PANIC_1, 4);
+		break;
+	case SOUND_PED_ROBBED:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_MUGGED_1, 2);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_FIGHT_1, 4);
+		break;
+	case SOUND_PED_EVADE:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_DODGE_1, 4);
+		break;
 	case SOUND_PED_CAR_COLLISION:
 		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 4);
 		break;
-	case SOUND_PED_CHAT_EVENT: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_SHOCKED_1, 2); break;
+	case SOUND_PED_CHAT_EVENT:
+		GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_SHOCKED_1, 2);
+		break;
 	case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_CHAT_1, 4); break;
 	default: return GetGenericFemaleTalkSfx(sound);
 	}
@@ -2054,10 +2548,15 @@ uint32
 cAudioManager::GetSpecialCharacterTalkSfx(int32 modelIndex, int32 sound)
 {
 	char *modelName = CModelInfo::GetModelInfo(modelIndex)->GetName();
-	if(!CGeneral::faststricmp(modelName, "eight") || !CGeneral::faststricmp(modelName, "eight2")) { return GetEightTalkSfx(sound); }
+	if(!CGeneral::faststricmp(modelName, "eight") ||
+	   !CGeneral::faststricmp(modelName, "eight2")) {
+		return GetEightTalkSfx(sound);
+	}
 	if(!CGeneral::faststricmp(modelName, "frankie")) { return GetFrankieTalkSfx(sound); }
 	if(!CGeneral::faststricmp(modelName, "misty")) { return GetMistyTalkSfx(sound); }
-	if(!CGeneral::faststricmp(modelName, "ojg") || !CGeneral::faststricmp(modelName, "ojg_p")) { return GetOJGTalkSfx(sound); }
+	if(!CGeneral::faststricmp(modelName, "ojg") || !CGeneral::faststricmp(modelName, "ojg_p")) {
+		return GetOJGTalkSfx(sound);
+	}
 	if(!CGeneral::faststricmp(modelName, "cat")) { return GetCatatalinaTalkSfx(sound); }
 	if(!CGeneral::faststricmp(modelName, "bomber")) { return GetBomberTalkSfx(sound); }
 	if(!CGeneral::faststricmp(modelName, "s_guard")) { return GetSecurityGuardTalkSfx(sound); }
@@ -2147,12 +2646,24 @@ cAudioManager::GetSecurityGuardTalkSfx(int16 sound)
 	static uint32 lastSfx = NO_SAMPLE;
 
 	switch(sound) {
-	case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_GUN_COOL_1, 2); break;
+	case SOUND_PED_HANDS_UP:
+		GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_GUN_COOL_1, 2);
+		break;
 	case SOUND_PED_HANDS_COWER: sfx = SFX_SECURITY_GUARD_VOICE_1_GUN_PANIC_1; break;
 	case SOUND_PED_CAR_JACKED:
-	case SOUND_PED_CAR_COLLISION: GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 6); break;
-	case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_FIGHT_1, 2); break;
-	case SOUND_PED_FLEE_RUN: GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 12); break;
+	case SOUND_PED_CAR_COLLISION:
+		GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 6);
+		break;
+	case SOUND_PED_ATTACK:
+		GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_FIGHT_1, 2);
+		break;
+	case SOUND_PED_FLEE_RUN:
+#ifdef FIX_BUGS
+		sfx = SFX_SECURITY_GUARD_VOICE_1_RUN_FROM_FIGHT_1;
+#else
+		GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 12);
+#endif
+		break;
 	default: return GetGenericMaleTalkSfx(sound);
 	}
 	return sfx;
@@ -2215,8 +2726,8 @@ cAudioManager::GenerateIntegerRandomNumberTable()
 char *
 cAudioManager::Get3DProviderName(uint8 id) const
 {
-	if(!m_bIsInitialised) return 0;
-	if(id >= SampleManager.GetNum3DProvidersAvailable()) return 0;
+	if(!m_bIsInitialised) return nil;
+	if(id >= SampleManager.GetNum3DProvidersAvailable()) return nil;
 	return SampleManager.Get3DProviderName(id);
 }
 
@@ -2368,8 +2879,8 @@ cAudioManager::GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint
 }
 
 float
-cAudioManager::GetVehicleDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile, cTransmission *transmission,
-                                             float velocityChange)
+cAudioManager::GetVehicleDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile,
+                                             cTransmission *transmission, float velocityChange)
 {
 	tWheelState wheelState;
 	float relativeVelChange;
@@ -2407,8 +2918,8 @@ cAudioManager::GetVehicleDriveWheelSkidValue(uint8 wheel, CAutomobile *automobil
 }
 
 float
-cAudioManager::GetVehicleNonDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile, cTransmission *transmission,
-                                                float velocityChange)
+cAudioManager::GetVehicleNonDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile,
+                                                cTransmission *transmission, float velocityChange)
 {
 	float relativeVelChange;
 
@@ -2424,7 +2935,8 @@ cAudioManager::GetVehicleNonDriveWheelSkidValue(uint8 wheel, CAutomobile *automo
 bool
 cAudioManager::HasAirBrakes(int32 model) const
 {
-	return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH;
+	return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS ||
+	       model == COACH;
 }
 
 void
@@ -2466,7 +2978,7 @@ cAudioManager::IsAudioInitialised() const
 bool
 cAudioManager::IsMissionAudioSampleFinished()
 {
-	if(m_bIsInitialised) return m_sMissionAudio.m_bPlayStatus == 2;
+	if(m_bIsInitialised) return m_sMissionAudio.m_bPlayStatus == PLAY_STATUS_FINISHED;
 
 	static int32 cPretendFrame = 1;
 
@@ -2504,7 +3016,8 @@ cAudioManager::MissionScriptAudioUsesPoliceChannel(int32 soundMission) const
 void
 cAudioManager::PlayLoadedMissionAudio()
 {
-	if(m_bIsInitialised && m_sMissionAudio.m_nSampleIndex != NO_SAMPLE && m_sMissionAudio.m_bLoadingStatus == 1 &&
+	if(m_bIsInitialised && m_sMissionAudio.m_nSampleIndex != NO_SAMPLE &&
+	   m_sMissionAudio.m_bLoadingStatus == LOADING_STATUS_LOADED &&
 	   !m_sMissionAudio.m_bPlayStatus) {
 		m_sMissionAudio.m_bIsPlayed = true;
 	}
@@ -2514,11 +3027,12 @@ void
 cAudioManager::PlayOneShot(int32 index, int16 sound, float vol)
 {
 	static const uint8 OneShotPriority[] = {
-	    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 3, 5, 2, 2, 1, 1, 3, 1, 3, 3, 1, 1, 1, 4, 4, 3, 1, 1,
-	    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 3, 2, 2, 2, 2, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	    1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 3, 1, 1, 1, 9,
-	    2, 2, 0, 0, 0, 0, 3, 3, 5, 1, 1, 1, 1, 3, 4, 7, 6, 6, 6, 6, 1, 3, 4, 3, 4, 2, 1, 3, 5, 4, 6, 6, 1, 3,
-	    1, 1, 1, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 3, 5, 2, 2, 1, 1, 3, 1, 3, 3, 1, 1,
+	    1, 4, 4, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 3, 2, 2, 2, 2, 0, 0, 6,
+	    6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 3, 1, 1, 1, 9, 2, 2, 0, 0, 0, 0, 3, 3, 5, 1,
+	    1, 1, 1, 3, 4, 7, 6, 6, 6, 6, 1, 3, 4, 3, 4, 2, 1, 3, 5, 4, 6, 6, 1, 3, 1, 1, 1, 0,
+	    0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 	if(m_bIsInitialised) {
 		if(index >= 0 && index < totalAudioEntitiesSlots) {
@@ -2526,37 +3040,48 @@ cAudioManager::PlayOneShot(int32 index, int16 sound, float vol)
 			if(entity.m_bIsUsed) {
 				if(sound < SOUND_TOTAL_SOUNDS) {
 					if(entity.m_nType == AUDIOTYPE_SCRIPTOBJECT) {
-						if(m_nScriptObjectEntityTotal < ARRAY_SIZE(m_anScriptObjectEntityIndices)) {
+						if(m_sAudioScriptObjectManager.m_nScriptObjectEntityTotal <
+						   ARRAY_SIZE(m_sAudioScriptObjectManager.m_anScriptObjectEntityIndices)) {
 							entity.m_awAudioEvent[0] = sound;
 							entity.m_AudioEvents = 1;
-							m_anScriptObjectEntityIndices[m_nScriptObjectEntityTotal++] =
-							    index;
+							m_sAudioScriptObjectManager.m_anScriptObjectEntityIndices
+							    [m_sAudioScriptObjectManager.m_nScriptObjectEntityTotal++] = index;
 						}
 					} else {
 						int32 i = 0;
 						while(true) {
 							if(i >= entity.m_AudioEvents) {
-								if(entity.m_AudioEvents < ARRAY_SIZE(entity.m_awAudioEvent)) {
-									entity.m_awAudioEvent[i] = sound;
+								if(entity.m_AudioEvents <
+								   ARRAY_SIZE(
+								       entity.m_awAudioEvent)) {
+									entity.m_awAudioEvent[i] =
+									    sound;
 									entity.m_afVolume[i] = vol;
 									++entity.m_AudioEvents;
 								}
 								return;
 							}
-							if(OneShotPriority[entity.m_awAudioEvent[i]] >
+							if(OneShotPriority[entity
+							                       .m_awAudioEvent[i]] >
 							   OneShotPriority[sound])
 								break;
 							++i;
 						}
-						if(i < 3) {
+						if(i < NUM_AUDIOENTITY_EVENTS - 1) {
 							memmove(&entity.m_awAudioEvent[i + 1],
-							        &entity.m_awAudioEvent[i], (3 - i) * 2);
-							memmove(&entity.m_afVolume[i + 1], &entity.m_afVolume[i],
-							        (3 - i) * 4);
+							        &entity.m_awAudioEvent[i],
+							        (NUM_AUDIOENTITY_EVENTS - 1 - i) *
+							            NUM_AUDIOENTITY_EVENTS / 2);
+							memmove(&entity.m_afVolume[i + 1],
+							        &entity.m_afVolume[i],
+							        (NUM_AUDIOENTITY_EVENTS - 1 - i) *
+							            NUM_AUDIOENTITY_EVENTS);
 						}
 						entity.m_awAudioEvent[i] = sound;
 						entity.m_afVolume[i] = vol;
-						if(entity.m_AudioEvents < ARRAY_SIZE(entity.m_awAudioEvent)) ++entity.m_AudioEvents;
+						if(entity.m_AudioEvents <
+						   ARRAY_SIZE(entity.m_awAudioEvent))
+							++entity.m_AudioEvents;
 					}
 				}
 			}
@@ -2582,31 +3107,31 @@ cAudioManager::PostInitialiseGameSpecificSetup()
 	m_nFireAudioEntity = CreateEntity(AUDIOTYPE_FIRE, &gFireManager);
 	if(m_nFireAudioEntity >= 0) SetEntityStatus(m_nFireAudioEntity, 1);
 
-	m_nCollisionEntity = CreateEntity(AUDIOTYPE_COLLISION, (void*)1);
+	m_nCollisionEntity = CreateEntity(AUDIOTYPE_COLLISION, (void *)1);
 	if(m_nCollisionEntity >= 0) SetEntityStatus(m_nCollisionEntity, 1);
 
-	m_nFrontEndEntity = CreateEntity(AUDIOTYPE_FRONTEND, (void*)1);
+	m_nFrontEndEntity = CreateEntity(AUDIOTYPE_FRONTEND, (void *)1);
 	if(m_nFrontEndEntity >= 0) SetEntityStatus(m_nFrontEndEntity, 1);
 
-	m_nProjectileEntity = CreateEntity(AUDIOTYPE_PROJECTILE, (void*)1);
+	m_nProjectileEntity = CreateEntity(AUDIOTYPE_PROJECTILE, (void *)1);
 	if(m_nProjectileEntity >= 0) SetEntityStatus(m_nProjectileEntity, 1);
 
-	m_nWaterCannonEntity = CreateEntity(AUDIOTYPE_WATERCANNON, (void*)1);
+	m_nWaterCannonEntity = CreateEntity(AUDIOTYPE_WATERCANNON, (void *)1);
 	if(m_nWaterCannonEntity >= 0) SetEntityStatus(m_nWaterCannonEntity, 1);
 
-	m_nPoliceChannelEntity = CreateEntity(AUDIOTYPE_POLICERADIO, (void*)1);
+	m_nPoliceChannelEntity = CreateEntity(AUDIOTYPE_POLICERADIO, (void *)1);
 	if(m_nPoliceChannelEntity >= 0) SetEntityStatus(m_nPoliceChannelEntity, 1);
 
-	m_nBridgeEntity = CreateEntity(AUDIOTYPE_BRIDGE, (void*)1);
+	m_nBridgeEntity = CreateEntity(AUDIOTYPE_BRIDGE, (void *)1);
 	if(m_nBridgeEntity >= 0) SetEntityStatus(m_nBridgeEntity, 1);
 
 	m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
-	m_sMissionAudio.m_bLoadingStatus = 0;
-	m_sMissionAudio.m_bPlayStatus = 0;
+	m_sMissionAudio.m_bLoadingStatus = LOADING_STATUS_NOT_LOADED;
+	m_sMissionAudio.m_bPlayStatus = PLAY_STATUS_STOPPED;
 	m_sMissionAudio.field_22 = 0;
 	m_sMissionAudio.m_bIsPlayed = false;
-	m_sMissionAudio.field_12 = 1;
-	m_sMissionAudio.field_24 = 0;
+	m_sMissionAudio.m_bPredefinedProperties = 1;
+	m_sMissionAudio.m_nMissionAudioCounter = 0;
 	ResetAudioLogicTimers(CTimer::GetTimeInMilliseconds());
 }
 
@@ -2685,7 +3210,8 @@ int32
 FindMissionAudioSfx(const char *name)
 {
 	for(uint32 i = 0; i < ARRAY_SIZE(MissionAudioNameSfxAssoc); ++i) {
-		if(!CGeneral::faststricmp(MissionAudioNameSfxAssoc[i].m_pName, name)) return MissionAudioNameSfxAssoc[i].m_nId;
+		if(!CGeneral::faststricmp(MissionAudioNameSfxAssoc[i].m_pName, name))
+			return MissionAudioNameSfxAssoc[i].m_nId;
 	}
 	debug("Can't find mission audio %s", name);
 	return NO_SAMPLE;
@@ -2698,19 +3224,19 @@ cAudioManager::PreloadMissionAudio(const char *name)
 		int32 missionAudioSfx = FindMissionAudioSfx(name);
 		if(missionAudioSfx != NO_SAMPLE) {
 			m_sMissionAudio.m_nSampleIndex = missionAudioSfx;
-			m_sMissionAudio.m_bLoadingStatus = 0;
-			m_sMissionAudio.m_bPlayStatus = 0;
+			m_sMissionAudio.m_bLoadingStatus = LOADING_STATUS_NOT_LOADED;
+			m_sMissionAudio.m_bPlayStatus = PLAY_STATUS_STOPPED;
 			m_sMissionAudio.field_22 = 0;
-			m_sMissionAudio.field_24 =
-			    field_19192 * SampleManager.GetStreamedFileLength(missionAudioSfx) / 1000;
-			m_sMissionAudio.field_24 *= 4;
+			m_sMissionAudio.m_nMissionAudioCounter =
+			    m_bTimeSpent * SampleManager.GetStreamedFileLength(missionAudioSfx) /
+			    1000;
+			m_sMissionAudio.m_nMissionAudioCounter *= 4;
 			m_sMissionAudio.m_bIsPlayed = false;
-			m_sMissionAudio.field_12 = 1;
-			g_bMissionAudioLoadFailed = 0;
+			m_sMissionAudio.m_bPredefinedProperties = 1;
+			g_bMissionAudioLoadFailed = false;
 		}
 	}
 }
-
 void
 cAudioManager::PreTerminateGameSpecificShutdown()
 {
@@ -2763,190 +3289,232 @@ cAudioManager::ProcessActiveQueues()
 	uint8 emittingVol;
 	CVector position;
 
-	for (int32 i = 0; i < m_bActiveSamples; i++) {
-		m_asSamples[m_bActiveSampleQueue][i].m_bIsProcessed = 0;
-		m_asActiveSamples[i].m_bIsProcessed = 0;
+	for(int32 i = 0; i < m_bActiveSamples; i++) {
+		m_asSamples[m_bActiveSampleQueue][i].m_bIsProcessed = false;
+		m_asActiveSamples[i].m_bIsProcessed = false;
 	}
 
-	for (int32 i = 0; i < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++i) {
-		tSound& sample = m_asSamples[m_bActiveSampleQueue][m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]];
-		if (sample.m_nSampleIndex != NO_SAMPLE) {
-			for (int32 j = 0; j < m_bActiveSamples; ++j) {
-				if (sample.m_nEntityIndex == m_asActiveSamples[j].m_nEntityIndex &&
-					sample.m_counter == m_asActiveSamples[j].m_counter &&
-					sample.m_nSampleIndex == m_asActiveSamples[j].m_nSampleIndex) {
-					if (sample.m_nLoopCount) {
-						if (m_FrameCounter & 1) {
+	for(int32 i = 0; i < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++i) {
+		tSound &sample = m_asSamples[m_bActiveSampleQueue]
+		                            [m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]];
+		if(sample.m_nSampleIndex != NO_SAMPLE) {
+			for(int32 j = 0; j < m_bActiveSamples; ++j) {
+				if(sample.m_nEntityIndex == m_asActiveSamples[j].m_nEntityIndex &&
+				   sample.m_nCounter == m_asActiveSamples[j].m_nCounter &&
+				   sample.m_nSampleIndex == m_asActiveSamples[j].m_nSampleIndex) {
+					if(sample.m_nLoopCount) {
+						if(m_FrameCounter & 1) {
 							flag = !!(j & 1);
-						}
-						else {
+						} else {
 							flag = !(j & 1);
 						}
-						if (flag && !SampleManager.GetChannelUsedFlag(j)) {
-							sample.m_bLoopEnded = 1;
-							m_asActiveSamples[j].m_bLoopEnded = 1;
-							m_asActiveSamples[j].m_nSampleIndex = NO_SAMPLE;
-							m_asActiveSamples[j].m_nEntityIndex = AEHANDLE_NONE;
+						if(flag && !SampleManager.GetChannelUsedFlag(j)) {
+							sample.m_bLoopEnded = true;
+							m_asActiveSamples[j].m_bLoopEnded = true;
+							m_asActiveSamples[j].m_nSampleIndex =
+							    NO_SAMPLE;
+							m_asActiveSamples[j].m_nEntityIndex =
+							    AEHANDLE_NONE;
 							continue;
 						}
 					}
-					sample.m_bIsProcessed = 1;
-					m_asActiveSamples[j].m_bIsProcessed = 1;
-					sample.field_88 = -1;
-					if (!sample.field_56) {
-						if (sample.m_bIsDistant) {
-							if (field_4) {
-								emittingVol = 2 * min(63, sample.m_bEmittingVolume);
+					sample.m_bIsProcessed = true;
+					m_asActiveSamples[j].m_bIsProcessed = true;
+					sample.m_nVolumeChange = -1;
+					if(!sample.m_bReleasingSoundFlag) {
+						if(sample.m_bIs2D) {
+							if(field_4) {
+								emittingVol =
+								    2 *
+								    min(63,
+								        sample.m_bEmittingVolume);
+							} else {
+								emittingVol =
+								    sample.m_bEmittingVolume;
 							}
-							else {
-								emittingVol = sample.m_bEmittingVolume;
-							}
-							SampleManager.SetChannelFrequency(j, sample.m_nFrequency);
-							SampleManager.SetChannelEmittingVolume(j, emittingVol);
-						}
-						else {
-							m_asActiveSamples[j].m_fDistance = sample.m_fDistance;
+							SampleManager.SetChannelFrequency(
+							    j, sample.m_nFrequency);
+							SampleManager.SetChannelEmittingVolume(
+							    j, emittingVol);
+						} else {
+							m_asActiveSamples[j].m_fDistance =
+							    sample.m_fDistance;
 							position2 = sample.m_fDistance;
-							position1 = m_asActiveSamples[j].m_fDistance;
-							sample.m_nFrequency = ComputeDopplerEffectedFrequency(
-								sample.m_nFrequency, position1, position2, sample.field_48);
-							if (sample.m_nFrequency != m_asActiveSamples[j].m_nFrequency) {
+							position1 =
+							    m_asActiveSamples[j].m_fDistance;
+							sample.m_nFrequency =
+							    ComputeDopplerEffectedFrequency(
+							        sample.m_nFrequency, position1,
+							        position2,
+							        sample.m_fSpeedMultiplier);
+							if(sample.m_nFrequency !=
+							   m_asActiveSamples[j].m_nFrequency) {
 								int32 freq;
-								if (sample.m_nFrequency <=
-									m_asActiveSamples[j].m_nFrequency) {
-									freq = max(sample.m_nFrequency,
-										m_asActiveSamples[j].m_nFrequency -
-										6000);
+								if(sample.m_nFrequency <=
+								   m_asActiveSamples[j]
+								       .m_nFrequency) {
+									freq = max(
+									    sample.m_nFrequency,
+									    m_asActiveSamples[j]
+									            .m_nFrequency -
+									        6000);
+								} else {
+									freq = min(
+									    sample.m_nFrequency,
+									    m_asActiveSamples[j]
+									            .m_nFrequency +
+									        6000);
 								}
-								else {
-									freq = min(sample.m_nFrequency,
-										m_asActiveSamples[j].m_nFrequency +
-										6000);
-								}
-								m_asActiveSamples[j].m_nFrequency = freq;
-								SampleManager.SetChannelFrequency(j, freq);
+								m_asActiveSamples[j].m_nFrequency =
+								    freq;
+								SampleManager.SetChannelFrequency(
+								    j, freq);
 							}
 
-							if (sample.m_bEmittingVolume !=
-								m_asActiveSamples[j].m_bEmittingVolume) {
-								if (sample.m_bEmittingVolume <=
-									m_asActiveSamples[j].m_bEmittingVolume) {
+							if(sample.m_bEmittingVolume !=
+							   m_asActiveSamples[j].m_bEmittingVolume) {
+								if(sample.m_bEmittingVolume <=
+								   m_asActiveSamples[j]
+								       .m_bEmittingVolume) {
 									vol = max(
-										m_asActiveSamples[j].m_bEmittingVolume - 10,
-										sample.m_bEmittingVolume);
-								}
-								else {
+									    m_asActiveSamples[j]
+									            .m_bEmittingVolume -
+									        10,
+									    sample
+									        .m_bEmittingVolume);
+								} else {
 									vol = min(
-										m_asActiveSamples[j].m_bEmittingVolume + 10,
-										sample.m_bEmittingVolume);
+									    m_asActiveSamples[j]
+									            .m_bEmittingVolume +
+									        10,
+									    sample
+									        .m_bEmittingVolume);
 								}
 
 								uint8 emittingVol;
-								if (field_4) {
-									emittingVol = 2 * min(63, vol);
-								}
-								else {
+								if(field_4) {
+									emittingVol =
+									    2 * min(63, vol);
+								} else {
 									emittingVol = vol;
 								}
-								SampleManager.SetChannelEmittingVolume(j, emittingVol);
-								m_asActiveSamples[j].m_bEmittingVolume = vol;
+								SampleManager
+								    .SetChannelEmittingVolume(
+								        j, emittingVol);
+								m_asActiveSamples[j]
+								    .m_bEmittingVolume = vol;
 							}
-							TranslateEntity(&sample.m_vecPos, &position);
-							SampleManager.SetChannel3DPosition(j, position.x, position.y,
-								position.z);
+							TranslateEntity(&sample.m_vecPos,
+							                &position);
+							SampleManager.SetChannel3DPosition(
+							    j, position.x, position.y, position.z);
 							SampleManager.SetChannel3DDistances(
-								j, sample.m_fSoundIntensity,
-								0.25f * sample.m_fSoundIntensity);
+							    j, sample.m_fSoundIntensity,
+							    0.25f * sample.m_fSoundIntensity);
 						}
-						SampleManager.SetChannelReverbFlag(j, sample.m_bReverbFlag);
+						SampleManager.SetChannelReverbFlag(
+						    j, sample.m_bReverbFlag);
 						continue;
 					}
-					sample.m_bIsProcessed = 0;
-					m_asActiveSamples[j].m_bIsProcessed = 0;
+					sample.m_bIsProcessed = false;
+					m_asActiveSamples[j].m_bIsProcessed = false;
 					break;
 				}
 			}
 		}
 	}
-	for (int32 i = 0; i < m_bActiveSamples; i++) {
-		if (m_asActiveSamples[i].m_nSampleIndex != NO_SAMPLE && !m_asActiveSamples[i].m_bIsProcessed) {
+	for(int32 i = 0; i < m_bActiveSamples; i++) {
+		if(m_asActiveSamples[i].m_nSampleIndex != NO_SAMPLE &&
+		   !m_asActiveSamples[i].m_bIsProcessed) {
 			SampleManager.StopChannel(i);
 			m_asActiveSamples[i].m_nSampleIndex = NO_SAMPLE;
-			m_asActiveSamples[i].m_nEntityIndex = -5;
+			m_asActiveSamples[i].m_nEntityIndex = AEHANDLE_NONE;
 		}
 	}
-	for (int32 i = 0; i < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++i) {
-
-		tSound& sample = m_asSamples[m_bActiveSampleQueue][m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]];
-		if (!sample.m_bIsProcessed && !sample.m_bLoopEnded &&
-			m_asAudioEntities[sample.m_nEntityIndex].m_bIsUsed && sample.m_nSampleIndex < NO_SAMPLE) {
-			if (sample.m_counter > 255 && sample.m_nLoopCount && sample.m_bLoopsRemaining) {
+	for(int32 i = 0; i < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; ++i) {
+		tSound &sample = m_asSamples[m_bActiveSampleQueue]
+		                            [m_abSampleQueueIndexTable[m_bActiveSampleQueue][i]];
+		if(!sample.m_bIsProcessed && !sample.m_bLoopEnded &&
+		   m_asAudioEntities[sample.m_nEntityIndex].m_bIsUsed &&
+		   sample.m_nSampleIndex < NO_SAMPLE) {
+			if(sample.m_nCounter > 255 && sample.m_nLoopCount &&
+			   sample.m_bLoopsRemaining) {
 				--sample.m_bLoopsRemaining;
-				sample.field_76 = 1;
-			}
-			else {
-				for (int32 j = 0; j < m_bActiveSamples; ++j) {
-					if (!m_asActiveSamples[j].m_bIsProcessed) {
-						if (sample.m_nLoopCount) {
-							v28 = sample.m_nFrequency / field_19192;
+				sample.m_nReleasingVolumeDivider = 1;
+			} else {
+				for(int32 j = 0; j < m_bActiveSamples; ++j) {
+					if(!m_asActiveSamples[j].m_bIsProcessed) {
+						if(sample.m_nLoopCount) {
+							v28 = sample.m_nFrequency / m_bTimeSpent;
 							v29 = sample.m_nLoopCount *
-								SampleManager.GetSampleLength(sample.m_nSampleIndex);
-							if (v28 == 0) continue;
-							sample.field_76 = v29 / v28 + 1;
+							      SampleManager.GetSampleLength(
+							          sample.m_nSampleIndex);
+							if(v28 == 0) continue;
+							sample.m_nReleasingVolumeDivider =
+							    v29 / v28 + 1;
 						}
-						memcpy(&m_asActiveSamples[j], &sample, sizeof(tSound));
-						if (!m_asActiveSamples[j].m_bIsDistant)
-							TranslateEntity(&m_asActiveSamples[j].m_vecPos, &position);
-						if (field_4) {
+						memcpy(&m_asActiveSamples[j], &sample,
+						       sizeof(tSound));
+						if(!m_asActiveSamples[j].m_bIs2D)
+							TranslateEntity(
+							    &m_asActiveSamples[j].m_vecPos,
+							    &position);
+						if(field_4) {
 							emittingVol =
-								2 * min(63, m_asActiveSamples[j].m_bEmittingVolume);
+							    2 * min(63, m_asActiveSamples[j]
+							                    .m_bEmittingVolume);
+						} else {
+							emittingVol =
+							    m_asActiveSamples[j].m_bEmittingVolume;
 						}
-						else {
-							emittingVol = m_asActiveSamples[j].m_bEmittingVolume;
-						}
-						if (SampleManager.InitialiseChannel(j,
-							m_asActiveSamples[j].m_nSampleIndex,
-							m_asActiveSamples[j].m_bBankIndex)) {
+						if(SampleManager.InitialiseChannel(
+						       j, m_asActiveSamples[j].m_nSampleIndex,
+						       m_asActiveSamples[j].m_bBankIndex)) {
 							SampleManager.SetChannelFrequency(
-								j, m_asActiveSamples[j].m_nFrequency);
-							SampleManager.SetChannelEmittingVolume(j, emittingVol);
+							    j, m_asActiveSamples[j].m_nFrequency);
+							SampleManager.SetChannelEmittingVolume(
+							    j, emittingVol);
 							SampleManager.SetChannelLoopPoints(
-								j, m_asActiveSamples[j].m_nLoopStart,
-								m_asActiveSamples[j].m_nLoopEnd);
+							    j, m_asActiveSamples[j].m_nLoopStart,
+							    m_asActiveSamples[j].m_nLoopEnd);
 							SampleManager.SetChannelLoopCount(
-								j, m_asActiveSamples[j].m_nLoopCount);
+							    j, m_asActiveSamples[j].m_nLoopCount);
 							SampleManager.SetChannelReverbFlag(
-								j, m_asActiveSamples[j].m_bReverbFlag);
-							if (m_asActiveSamples[j].m_bIsDistant) {
-								uint8 offset = m_asActiveSamples[j].m_bOffset;
-								if (offset == 63) {
+							    j, m_asActiveSamples[j].m_bReverbFlag);
+							if(m_asActiveSamples[j].m_bIs2D) {
+								uint8 offset =
+								    m_asActiveSamples[j].m_bOffset;
+								if(offset == 63) {
 									x = 0.f;
-								}
-								else if (offset >= 63) {
-									x = (offset - 63) * 1000.f / 63;
-								}
-								else {
-									x = -(63 - offset) * 1000.f / 63;
+								} else if(offset >= 63) {
+									x = (offset - 63) * 1000.f /
+									    63;
+								} else {
+									x = -(63 - offset) *
+									    1000.f / 63;
 								}
 								usedX = x;
 								usedY = 0.f;
 								usedZ = 0.f;
-								m_asActiveSamples[j].m_fSoundIntensity = 100000.0f;
-							}
-							else {
+								m_asActiveSamples[j]
+								    .m_fSoundIntensity = 100000.0f;
+							} else {
 								usedX = position.x;
 								usedY = position.y;
 								usedZ = position.z;
 							}
-							SampleManager.SetChannel3DPosition(j, usedX, usedY, usedZ);
+							SampleManager.SetChannel3DPosition(
+							    j, usedX, usedY, usedZ);
 							SampleManager.SetChannel3DDistances(
-								j, m_asActiveSamples[j].m_fSoundIntensity,
-								0.25f * m_asActiveSamples[j].m_fSoundIntensity);
+							    j,
+							    m_asActiveSamples[j].m_fSoundIntensity,
+							    0.25f * m_asActiveSamples[j]
+							                .m_fSoundIntensity);
 							SampleManager.StartChannel(j);
 						}
-						m_asActiveSamples[j].m_bIsProcessed = 1;
-						sample.m_bIsProcessed = 1;
-						sample.field_88 = -1;
+						m_asActiveSamples[j].m_bIsProcessed = true;
+						sample.m_bIsProcessed = true;
+						sample.m_nVolumeChange = -1;
 						break;
 					}
 				}
@@ -2965,7 +3533,8 @@ cAudioManager::ProcessAirBrakes(cVehicleParams *params)
 	automobile = (CAutomobile *)params->m_pVehicle;
 	if(!automobile->bEngineOn) return true;
 
-	if((automobile->m_fVelocityChangeForAudio < 0.025f || params->m_fVelocityChange >= 0.025f) &&
+	if((automobile->m_fVelocityChangeForAudio < 0.025f ||
+	    params->m_fVelocityChange >= 0.025f) &&
 	   (automobile->m_fVelocityChangeForAudio > -0.025f || params->m_fVelocityChange <= 0.025f))
 		return true;
 
@@ -2973,20 +3542,20 @@ cAudioManager::ProcessAirBrakes(cVehicleParams *params)
 	rand = m_anRandomTable[0] % 10 + 70;
 	m_sQueueSample.m_bVolume = ComputeVolume(rand, 30.0f, m_sQueueSample.m_fDistance);
 	if(m_sQueueSample.m_bVolume) {
-		m_sQueueSample.m_counter = 13;
+		m_sQueueSample.m_nCounter = 13;
 		m_sQueueSample.m_nSampleIndex = SFX_AIR_BRAKES;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_AIR_BRAKES);
 		m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = false;
-		m_sQueueSample.field_16 = 10;
+		m_sQueueSample.m_bIs2D = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 10;
 		m_sQueueSample.m_nLoopCount = 1;
 		m_sQueueSample.m_bEmittingVolume = rand;
 		m_sQueueSample.m_nLoopStart = 0;
 		m_sQueueSample.m_nLoopEnd = -1;
-		m_sQueueSample.field_48 = 0.0f;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
-		m_sQueueSample.field_56 = 1;
+		m_sQueueSample.m_bReleasingSoundFlag = true;
 		m_sQueueSample.m_bReverbFlag = true;
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
@@ -3014,19 +3583,20 @@ cAudioManager::ProcessAirportScriptObject(uint8 sound)
 		float distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 		if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 			m_sQueueSample.m_fDistance = Sqrt(distSquared);
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(110, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    110, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_nSampleIndex = (m_anRandomTable[1] & 3) + SFX_AIRPORT_ANNOUNCEMENT_1;
+				m_sQueueSample.m_nSampleIndex =
+				    (m_anRandomTable[1] & 3) + SFX_AIRPORT_ANNOUNCEMENT_1;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_counter = counter++;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nCounter = counter++;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 2.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 				m_sQueueSample.m_bEmittingVolume = 110;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
@@ -3058,25 +3628,28 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params)
 		boat = (CBoat *)params->m_pVehicle;
 		if(params->m_nIndex == REEFER) {
 			CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
-			m_sQueueSample.m_bVolume = ComputeVolume(80, 50.f, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(80, 50.f, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_counter = 39;
+				m_sQueueSample.m_nCounter = 39;
 				m_sQueueSample.m_nSampleIndex = SFX_FISHING_BOAT_IDLE;
 				m_sQueueSample.m_nFrequency = 10386;
-				m_sQueueSample.m_nFrequency += (m_sQueueSample.m_nEntityIndex << 16) % 1000;
+				m_sQueueSample.m_nFrequency +=
+				    (m_sQueueSample.m_nEntityIndex << 16) % 1000;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 3;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
 				m_sQueueSample.m_nLoopCount = 0;
 				m_sQueueSample.m_bEmittingVolume = 80;
 				m_sQueueSample.m_nLoopStart =
-				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.field_48 = 2.0f;
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 				m_sQueueSample.m_fSoundIntensity = intensity;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_76 = 7;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
+				m_sQueueSample.m_nReleasingVolumeDivider = 7;
 				m_sQueueSample.m_bReverbFlag = true;
 				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
@@ -3090,7 +3663,8 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params)
 				emittingVol = (100.f * padRelativeAccerate) + 15;
 				m_sQueueSample.m_nFrequency = (3000.f * padRelativeAccerate) + 6000;
 				if(!boat->m_bIsAnchored)
-					m_sQueueSample.m_nFrequency = 11 * m_sQueueSample.m_nFrequency / 10;
+					m_sQueueSample.m_nFrequency =
+					    11 * m_sQueueSample.m_nFrequency / 10;
 			} else {
 				gasPedal = Abs(boat->m_fGasPedal);
 				if(gasPedal > 0.0f) {
@@ -3100,26 +3674,29 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params)
 					emittingVol = (100.f * gasPedal) + 15;
 					m_sQueueSample.m_nFrequency = (3000.f * gasPedal) + 6000;
 					if(!boat->m_bIsAnchored)
-						m_sQueueSample.m_nFrequency = 11 * m_sQueueSample.m_nFrequency / 10;
+						m_sQueueSample.m_nFrequency =
+						    11 * m_sQueueSample.m_nFrequency / 10;
 				}
 			}
-			m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance);
 			if(!m_sQueueSample.m_bVolume) return 1;
-			m_sQueueSample.m_counter = 40;
+			m_sQueueSample.m_nCounter = 40;
 			m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_ACCEL;
 			m_sQueueSample.m_nFrequency += (m_sQueueSample.m_nEntityIndex << 16) % 1000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 3;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = intensity;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 7;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 7;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 		} else {
@@ -3131,18 +3708,21 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params)
 				if(padAccelerate <= 20) {
 					emittingVol = 45 - 45 * padAccelerate / 40;
 					m_sQueueSample.m_nFrequency = 100 * padAccelerate + 11025;
-					m_sQueueSample.m_counter = 39;
+					m_sQueueSample.m_nCounter = 39;
 					m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_IDLE;
 					if(LastAccel > 20) {
 						oneShotVol = LastVol;
-						PlayOneShot(m_sQueueSample.m_nEntityIndex, SOUND_17, oneShotVol);
+						PlayOneShot(m_sQueueSample.m_nEntityIndex, SOUND_17,
+						            oneShotVol);
 					}
 				} else {
 					emittingVol = 105 * padAccelerate / 255 + 15;
-					m_sQueueSample.m_nFrequency = 4000 * padAccelerate / 255 + 8000;
+					m_sQueueSample.m_nFrequency =
+					    4000 * padAccelerate / 255 + 8000;
 					if(!boat->m_bIsAnchored)
-						m_sQueueSample.m_nFrequency = 11 * m_sQueueSample.m_nFrequency / 10;
-					m_sQueueSample.m_counter = 40;
+						m_sQueueSample.m_nFrequency =
+						    11 * m_sQueueSample.m_nFrequency / 10;
+					m_sQueueSample.m_nCounter = 40;
 					m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_ACCEL;
 				}
 				LastVol = emittingVol;
@@ -3152,33 +3732,36 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params)
 				if(gasPedal > 0.0f) {
 					m_sQueueSample.m_nFrequency = 11025;
 					emittingVol = 45;
-					m_sQueueSample.m_counter = 39;
+					m_sQueueSample.m_nCounter = 39;
 					m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_IDLE;
 				} else {
 					emittingVol = (105.f * gasPedal) + 15;
 					m_sQueueSample.m_nFrequency = (4000.f * gasPedal) + 8000;
 					if(!boat->m_bIsAnchored)
-						m_sQueueSample.m_nFrequency = 11 * m_sQueueSample.m_nFrequency / 10;
-					m_sQueueSample.m_counter = 40;
+						m_sQueueSample.m_nFrequency =
+						    11 * m_sQueueSample.m_nFrequency / 10;
+					m_sQueueSample.m_nCounter = 40;
 					m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_ACCEL;
 				}
 			}
 			CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
-			m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance);
 			if(!m_sQueueSample.m_bVolume) return 1;
 			m_sQueueSample.m_nFrequency += (m_sQueueSample.m_nEntityIndex << 16) % 1000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 3;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = intensity;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 7;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 7;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 		}
@@ -3206,20 +3789,22 @@ cAudioManager::ProcessBoatMovingOverWater(cVehicleParams *params)
 	vol = (30.f * multiplier);
 	m_sQueueSample.m_bVolume = ComputeVolume(vol, 50.f, m_sQueueSample.m_fDistance);
 	if(m_sQueueSample.m_bVolume) {
-		m_sQueueSample.m_counter = 38;
+		m_sQueueSample.m_nCounter = 38;
 		m_sQueueSample.m_nSampleIndex = SFX_BOAT_WATER_LOOP;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = false;
-		m_sQueueSample.field_16 = 3;
+		m_sQueueSample.m_bIs2D = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
 		m_sQueueSample.m_nFrequency = (6050.f * multiplier) + 16000;
 		m_sQueueSample.m_nLoopCount = 0;
 		m_sQueueSample.m_bEmittingVolume = vol;
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		m_sQueueSample.m_fSoundIntensity = 50.0f;
-		m_sQueueSample.field_56 = 0;
-		m_sQueueSample.field_76 = 3;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
 		m_sQueueSample.m_bReverbFlag = true;
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
@@ -3259,23 +3844,26 @@ void
 cAudioManager::ProcessBridgeMotor()
 {
 	if(m_sQueueSample.m_fDistance < bridgeIntensity) {
-		m_sQueueSample.m_bVolume = ComputeVolume(maxVolume, bridgeIntensity, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume =
+		    ComputeVolume(maxVolume, bridgeIntensity, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 1;
-			m_sQueueSample.m_nSampleIndex = SFX_FISHING_BOAT_IDLE; // todo check sfx name
+			m_sQueueSample.m_nCounter = 1;
+			m_sQueueSample.m_nSampleIndex =
+			    SFX_FISHING_BOAT_IDLE; // todo check sfx name
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
 			m_sQueueSample.m_nFrequency = 5500;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = maxVolume;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = bridgeIntensity;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 3;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
 			m_sQueueSample.m_bReverbFlag = false;
 			AddSampleToRequestedQueue();
 		}
@@ -3285,10 +3873,12 @@ cAudioManager::ProcessBridgeMotor()
 void
 cAudioManager::ProcessBridgeOneShots()
 {
-	if(CBridge::State == STATE_LIFT_PART_IS_UP && CBridge::OldState == STATE_LIFT_PART_MOVING_UP) {
+	if(CBridge::State == STATE_LIFT_PART_IS_UP &&
+	   CBridge::OldState == STATE_LIFT_PART_MOVING_UP) {
 		m_sQueueSample.m_nSampleIndex = SFX_COL_CONTAINER_1;
 	} else {
-		if(CBridge::State == STATE_LIFT_PART_IS_DOWN && CBridge::OldState == STATE_LIFT_PART_MOVING_DOWN) {
+		if(CBridge::State == STATE_LIFT_PART_IS_DOWN &&
+		   CBridge::OldState == STATE_LIFT_PART_MOVING_DOWN) {
 			m_sQueueSample.m_nSampleIndex = SFX_COL_CONTAINER_1;
 		} else {
 			if(CBridge::State == STATE_LIFT_PART_MOVING_UP &&
@@ -3304,21 +3894,22 @@ cAudioManager::ProcessBridgeOneShots()
 		}
 	}
 	if(m_sQueueSample.m_fDistance < bridgeIntensity) {
-		m_sQueueSample.m_bVolume = ComputeVolume(maxVolume, bridgeIntensity, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume =
+		    ComputeVolume(maxVolume, bridgeIntensity, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 2;
+			m_sQueueSample.m_nCounter = 2;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
 			m_sQueueSample.m_nFrequency =
 			    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_nLoopCount = 1;
 			m_sQueueSample.m_bEmittingVolume = maxVolume;
 			m_sQueueSample.m_nLoopStart = 0;
 			m_sQueueSample.m_nLoopEnd = -1;
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = bridgeIntensity;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bReleasingSoundFlag = true;
 			m_sQueueSample.m_bReverbFlag = false;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -3332,21 +3923,23 @@ cAudioManager::ProcessBridgeWarning()
 	if(CStats::CommercialPassed && m_sQueueSample.m_fDistance < 450.f) {
 		m_sQueueSample.m_bVolume = ComputeVolume(100, 450.f, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 0;
+			m_sQueueSample.m_nCounter = 0;
 			m_sQueueSample.m_nSampleIndex = SFX_BRIDGE_OPEN_WARNING;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 1;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_BRIDGE_OPEN_WARNING);
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_BRIDGE_OPEN_WARNING);
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = 100;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = 450.0f;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 8;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 8;
 			m_sQueueSample.m_bReverbFlag = false;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -3365,21 +3958,23 @@ cAudioManager::ProcessCarBombTick(cVehicleParams *params)
 		CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 		m_sQueueSample.m_bVolume = ComputeVolume(60, 40.f, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 35;
+			m_sQueueSample.m_nCounter = 35;
 			m_sQueueSample.m_nSampleIndex = SFX_COUNTDOWN;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 0;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_COUNTDOWN);
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 0;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_COUNTDOWN);
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = 60;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = 40.0f;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 3;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -3402,9 +3997,10 @@ cAudioManager::ProcessCesna(cVehicleParams *params)
 			} else if(nAccel < 60) {
 				++nAccel;
 			}
-			AddPlayerCarSample(85 * (60 - nAccel) / 60 + 20, 8500 * nAccel / 60 + 17000, SFX_CESNA_IDLE, 0,
-			                   52, 1);
-			AddPlayerCarSample(85 * nAccel / 60 + 20, 8500 * nAccel / 60 + 17000, SFX_CESNA_REV, 0, 2, 1);
+			AddPlayerCarSample(85 * (60 - nAccel) / 60 + 20, 8500 * nAccel / 60 + 17000,
+			                   SFX_CESNA_IDLE, 0, 52, 1);
+			AddPlayerCarSample(85 * nAccel / 60 + 20, 8500 * nAccel / 60 + 17000,
+			                   SFX_CESNA_REV, 0, 2, 1);
 		}
 	} else if(params->m_nIndex == DODO) {
 		AddPlayerCarSample(105, 17000, SFX_CESNA_IDLE, 0, 52, 1);
@@ -3412,44 +4008,47 @@ cAudioManager::ProcessCesna(cVehicleParams *params)
 		CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 		m_sQueueSample.m_bVolume = ComputeVolume(80, 200.f, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 52;
+			m_sQueueSample.m_nCounter = 52;
 			m_sQueueSample.m_nSampleIndex = SFX_CESNA_IDLE;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 0;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 0;
 			m_sQueueSample.m_nFrequency = 12500;
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_76 = 8;
+			m_sQueueSample.m_nReleasingVolumeDivider = 8;
 			m_sQueueSample.m_bEmittingVolume = 80;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 8.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 8.0f;
 			m_sQueueSample.m_fSoundIntensity = 200.0f;
-			m_sQueueSample.field_56 = 0;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
 		}
 		if(params->m_fDistance < 8100.f) {
-			m_sQueueSample.m_bVolume = ComputeVolume(80, 90.f, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(80, 90.f, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_counter = 2;
+				m_sQueueSample.m_nCounter = 2;
 				m_sQueueSample.m_nSampleIndex = SFX_CESNA_REV;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 0;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 0;
 				m_sQueueSample.m_nFrequency = 25000;
 				m_sQueueSample.m_nLoopCount = 0;
-				m_sQueueSample.field_76 = 4;
+				m_sQueueSample.m_nReleasingVolumeDivider = 4;
 				m_sQueueSample.m_bEmittingVolume = 80;
 				m_sQueueSample.m_nLoopStart =
-				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.field_48 = 8.0f;
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_fSpeedMultiplier = 8.0f;
 				m_sQueueSample.m_fSoundIntensity = 90.0f;
-				m_sQueueSample.field_56 = 0;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
 				m_sQueueSample.m_bReverbFlag = true;
 				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
@@ -3480,20 +4079,21 @@ cAudioManager::ProcessCinemaScriptObject(uint8 sound)
 		if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 			m_sQueueSample.m_fDistance = Sqrt(distSquared);
 			rand = m_anRandomTable[0] % 90 + 30;
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
 				m_sQueueSample.m_nSampleIndex = counter % 3 + SFX_CINEMA_BASS_1;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 4);
-				m_sQueueSample.m_counter = counter++;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency / 4);
+				m_sQueueSample.m_nCounter = counter++;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 2.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 				m_sQueueSample.m_bEmittingVolume = rand;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
@@ -3515,41 +4115,46 @@ cAudioManager::ProcessCrane()
 	static const int intensity = 80;
 
 	if(crane) {
-		if(crane->m_bCraneActive == 1) {
-			if(crane->m_bCraneStatus) {
-				m_sQueueSample.m_vecPos = crane->m_pObject->GetPosition();
+		if(crane->m_nCraneStatus == CCrane::ACTIVATED) {
+			if(crane->m_nCraneState != CCrane::IDLE) {
+				m_sQueueSample.m_vecPos = crane->m_pCraneEntity->GetPosition();
 				distSquared = GetDistanceSquared(&this->m_sQueueSample.m_vecPos);
 				if(distSquared < SQR(intensity)) {
 					CalculateDistance(distCalculated, distSquared);
-					m_sQueueSample.m_bVolume = ComputeVolume(100, 80.f, m_sQueueSample.m_fDistance);
+					m_sQueueSample.m_bVolume =
+					    ComputeVolume(100, 80.f, m_sQueueSample.m_fDistance);
 					if(m_sQueueSample.m_bVolume) {
-						m_sQueueSample.m_counter = 0;
+						m_sQueueSample.m_nCounter = 0;
 						m_sQueueSample.m_nSampleIndex = SFX_CRANE_MAGNET;
 						m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-						m_sQueueSample.m_bIsDistant = false;
-						m_sQueueSample.field_16 = 2;
+						m_sQueueSample.m_bIs2D = false;
+						m_sQueueSample.m_nReleasingVolumeModificator = 2;
 						m_sQueueSample.m_nFrequency = 6000;
 						m_sQueueSample.m_nLoopCount = 0;
 						m_sQueueSample.m_bEmittingVolume = 100;
-						m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(
-						    m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_nLoopStart =
+						    SampleManager.GetSampleLoopStartOffset(
+						        m_sQueueSample.m_nSampleIndex);
 						m_sQueueSample.m_nLoopEnd =
-						    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-						m_sQueueSample.field_48 = 4.0f;
+						    SampleManager.GetSampleLoopEndOffset(
+						        m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 						m_sQueueSample.m_fSoundIntensity = intensity;
-						m_sQueueSample.field_56 = 0;
-						m_sQueueSample.field_76 = 3;
+						m_sQueueSample.m_bReleasingSoundFlag = false;
+						m_sQueueSample.m_nReleasingVolumeDivider = 3;
 						m_sQueueSample.m_bReverbFlag = true;
 						m_sQueueSample.m_bRequireReflection = false;
 						AddSampleToRequestedQueue();
 					}
-					if(m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_AudioEvents) {
-						m_sQueueSample.m_counter = 1;
+					if(m_asAudioEntities[m_sQueueSample.m_nEntityIndex]
+					       .m_AudioEvents) {
+						m_sQueueSample.m_nCounter = 1;
 						m_sQueueSample.m_nSampleIndex = SFX_COL_CAR_2;
 						m_sQueueSample.m_nFrequency =
-						    SampleManager.GetSampleBaseFrequency(SFX_COL_CAR_2);
+						    SampleManager.GetSampleBaseFrequency(
+						        SFX_COL_CAR_2);
 						m_sQueueSample.m_nLoopCount = 1;
-						m_sQueueSample.field_56 = 1;
+						m_sQueueSample.m_bReleasingSoundFlag = true;
 						m_sQueueSample.m_bReverbFlag = true;
 						m_sQueueSample.m_bRequireReflection = true;
 						AddSampleToRequestedQueue();
@@ -3584,19 +4189,21 @@ cAudioManager::ProcessDocksScriptObject(uint8 sound)
 		if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 			m_sQueueSample.m_fDistance = Sqrt(distSquared);
 			rand = m_anRandomTable[0] % 60 + 40;
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
 				m_sQueueSample.m_nSampleIndex = SFX_DOCKS_FOGHORN;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_DOCKS_FOGHORN);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
-				m_sQueueSample.m_counter = counter++;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency =
+				    SampleManager.GetSampleBaseFrequency(SFX_DOCKS_FOGHORN);
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
+				m_sQueueSample.m_nCounter = counter++;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 2.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 				m_sQueueSample.m_bEmittingVolume = rand;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
@@ -3624,29 +4231,32 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params)
 		if(engineStatus < 225) {
 			m_sQueueSample.m_nSampleIndex = SFX_JUMBO_TAXI;
 			emittingVolume = 6;
-			m_sQueueSample.field_16 = 7;
+			m_sQueueSample.m_nReleasingVolumeModificator = 7;
 			m_sQueueSample.m_nFrequency = 40000;
 		} else {
 			emittingVolume = 60;
 			m_sQueueSample.m_nSampleIndex = SFX_CAR_ON_FIRE;
-			m_sQueueSample.field_16 = 7;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE);
+			m_sQueueSample.m_nReleasingVolumeModificator = 7;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE);
 		}
 		CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
-		m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, engineDamageIntensity, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume = ComputeVolume(emittingVolume, engineDamageIntensity,
+		                                         m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 28;
+			m_sQueueSample.m_nCounter = 28;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
+			m_sQueueSample.m_bIs2D = false;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = emittingVolume;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = engineDamageIntensity;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 3;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -3752,14 +4362,14 @@ cAudioManager::ProcessExplosions(int32 explosion)
 				m_sQueueSample.m_fSoundIntensity = 400.0f;
 				m_sQueueSample.m_nSampleIndex = SFX_EXPLOSION_2;
 				m_sQueueSample.m_nFrequency = RandomDisplacement(2000) + 38000;
-				m_sQueueSample.field_16 = 0;
+				m_sQueueSample.m_nReleasingVolumeModificator = 0;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 				break;
 			case EXPLOSION_MOLOTOV:
 				m_sQueueSample.m_fSoundIntensity = 200.0f;
 				m_sQueueSample.m_nSampleIndex = SFX_EXPLOSION_3;
 				m_sQueueSample.m_nFrequency = RandomDisplacement(1000) + 19000;
-				m_sQueueSample.field_16 = 0;
+				m_sQueueSample.m_nReleasingVolumeModificator = 0;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 				break;
 			case EXPLOSION_MINE:
@@ -3767,7 +4377,7 @@ cAudioManager::ProcessExplosions(int32 explosion)
 				m_sQueueSample.m_fSoundIntensity = 300.0f;
 				m_sQueueSample.m_nSampleIndex = SFX_ROCKET_LEFT;
 				m_sQueueSample.m_nFrequency = RandomDisplacement(1000) + 12347;
-				m_sQueueSample.field_16 = 0;
+				m_sQueueSample.m_nReleasingVolumeModificator = 0;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 				break;
 			default:
@@ -3775,8 +4385,9 @@ cAudioManager::ProcessExplosions(int32 explosion)
 				m_sQueueSample.m_nSampleIndex = SFX_EXPLOSION_1;
 				m_sQueueSample.m_nFrequency = RandomDisplacement(2000) + 38000;
 				if(type == EXPLOSION_HELI)
-					m_sQueueSample.m_nFrequency = 8 * m_sQueueSample.m_nFrequency / 10;
-				m_sQueueSample.field_16 = 0;
+					m_sQueueSample.m_nFrequency =
+					    8 * m_sQueueSample.m_nFrequency / 10;
+				m_sQueueSample.m_nReleasingVolumeModificator = 0;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 				break;
 			}
@@ -3785,14 +4396,15 @@ cAudioManager::ProcessExplosions(int32 explosion)
 			distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 			if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 				m_sQueueSample.m_fDistance = Sqrt(distSquared);
-				m_sQueueSample.m_bVolume = ComputeVolume(maxVolume, m_sQueueSample.m_fSoundIntensity,
-				                                         m_sQueueSample.m_fDistance);
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(maxVolume, m_sQueueSample.m_fSoundIntensity,
+				                  m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
-					m_sQueueSample.m_counter = i;
-					m_sQueueSample.field_48 = 2.0f;
-					m_sQueueSample.m_bIsDistant = false;
+					m_sQueueSample.m_nCounter = i;
+					m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+					m_sQueueSample.m_bIs2D = false;
 					m_sQueueSample.m_nLoopCount = 1;
-					m_sQueueSample.field_56 = 1;
+					m_sQueueSample.m_bReleasingSoundFlag = true;
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bEmittingVolume = maxVolume;
 					m_sQueueSample.m_nLoopStart = 0;
@@ -3813,27 +4425,29 @@ cAudioManager::ProcessFireHydrant()
 	bool distCalculated = false;
 	static const int intensity = 35;
 
-	m_sQueueSample.m_vecPos = ((CEntity*)m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity)->GetPosition();
+	m_sQueueSample.m_vecPos =
+	    ((CEntity *)m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity)->GetPosition();
 	distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 	if(distSquared < SQR(intensity)) {
 		CalculateDistance(distCalculated, distSquared);
 		m_sQueueSample.m_bVolume = ComputeVolume(40, 35.f, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 0;
+			m_sQueueSample.m_nCounter = 0;
 			m_sQueueSample.m_nSampleIndex = SFX_JUMBO_TAXI;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 4;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 4;
 			m_sQueueSample.m_nFrequency = 15591;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = 40;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_fSoundIntensity = intensity;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 3;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -3857,9 +4471,12 @@ void cAudioManager::ProcessFires(int32)
 					m_sQueueSample.m_nSampleIndex = SFX_CAR_ON_FIRE;
 					emittingVol = 100;
 					m_sQueueSample.m_nFrequency =
-					    8 * SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE) / 10;
-					m_sQueueSample.m_nFrequency += i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
-					m_sQueueSample.field_16 = 6;
+					    8 *
+					    SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE) /
+					    10;
+					m_sQueueSample.m_nFrequency +=
+					    i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
+					m_sQueueSample.m_nReleasingVolumeModificator = 6;
 					break;
 				case ENTITY_TYPE_PED:
 					m_sQueueSample.m_fSoundIntensity = 25.0f;
@@ -3867,45 +4484,52 @@ void cAudioManager::ProcessFires(int32)
 					m_sQueueSample.m_nFrequency =
 					    SampleManager.GetSampleBaseFrequency(SFX_PED_ON_FIRE);
 					emittingVol = 60;
-					m_sQueueSample.m_nFrequency += i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
-					m_sQueueSample.field_16 = 10;
+					m_sQueueSample.m_nFrequency +=
+					    i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
+					m_sQueueSample.m_nReleasingVolumeModificator = 10;
 					break;
 				default:
 					m_sQueueSample.m_fSoundIntensity = 50.0f;
 					m_sQueueSample.m_nSampleIndex = SFX_CAR_ON_FIRE;
 					m_sQueueSample.m_nFrequency =
 					    SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE);
-					m_sQueueSample.m_nFrequency += i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
+					m_sQueueSample.m_nFrequency +=
+					    i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
 					emittingVol = 80;
-					m_sQueueSample.field_16 = 8;
+					m_sQueueSample.m_nReleasingVolumeModificator = 8;
 				}
 			} else {
 				m_sQueueSample.m_fSoundIntensity = 50.0f;
 				m_sQueueSample.m_nSampleIndex = SFX_CAR_ON_FIRE;
-				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE);
-				m_sQueueSample.m_nFrequency += i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
+				m_sQueueSample.m_nFrequency =
+				    SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE);
+				m_sQueueSample.m_nFrequency +=
+				    i * ((uint32)m_sQueueSample.m_nFrequency >> 6);
 				emittingVol = 80;
-				m_sQueueSample.field_16 = 8;
+				m_sQueueSample.m_nReleasingVolumeModificator = 8;
 			}
 			m_sQueueSample.m_vecPos = gFireManager.m_aFires[i].m_vecPos;
 			distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 			if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 				m_sQueueSample.m_fDistance = Sqrt(distSquared);
-				m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
-				                                         m_sQueueSample.m_fDistance);
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
+				                  m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
-					m_sQueueSample.m_counter = i;
+					m_sQueueSample.m_nCounter = i;
 					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-					m_sQueueSample.field_48 = 2.0f;
-					m_sQueueSample.field_76 = 10;
-					m_sQueueSample.m_bIsDistant = false;
+					m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+					m_sQueueSample.m_nReleasingVolumeDivider = 10;
+					m_sQueueSample.m_bIs2D = false;
 					m_sQueueSample.m_nLoopCount = 0;
-					m_sQueueSample.field_56 = 0;
+					m_sQueueSample.m_bReleasingSoundFlag = false;
 					m_sQueueSample.m_bEmittingVolume = emittingVol;
 					m_sQueueSample.m_nLoopStart =
-					    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopStartOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_nLoopEnd =
-					    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopEndOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bRequireReflection = false;
 					AddSampleToRequestedQueue();
@@ -3932,7 +4556,9 @@ cAudioManager::ProcessFrontEnd()
 		stereo = false;
 		processedMission = false;
 		switch(m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i]) {
-		case SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM: m_sQueueSample.m_nSampleIndex = SFX_ERROR_FIRE_RIFLE; break;
+		case SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM:
+			m_sQueueSample.m_nSampleIndex = SFX_ERROR_FIRE_RIFLE;
+			break;
 		case SOUND_WEAPON_ROCKET_SHOT_NO_ZOOM:
 			m_sQueueSample.m_nSampleIndex = SFX_ERROR_FIRE_ROCKET_LAUNCHER;
 			break;
@@ -3985,7 +4611,9 @@ cAudioManager::ProcessFrontEnd()
 		case SOUND_RACE_START_2:
 		case SOUND_RACE_START_1:
 		case SOUND_CLOCK_TICK: m_sQueueSample.m_nSampleIndex = SFX_TIMER_BEEP; break;
-		case SOUND_RACE_START_GO: m_sQueueSample.m_nSampleIndex = SFX_PART_MISSION_COMPLETE; break;
+		case SOUND_RACE_START_GO:
+			m_sQueueSample.m_nSampleIndex = SFX_PART_MISSION_COMPLETE;
+			break;
 		case SOUND_PART_MISSION_COMPLETE:
 			m_sQueueSample.m_nSampleIndex = SFX_PART_MISSION_COMPLETE;
 			processedMission = true;
@@ -4023,7 +4651,9 @@ cAudioManager::ProcessFrontEnd()
 			stereo = true;
 			break;
 		case SOUND_FRONTEND_NO_RADIO:
-		case SOUND_FRONTEND_RADIO_CHANGE: m_sQueueSample.m_nSampleIndex = SFX_RADIO_CLICK; break;
+		case SOUND_FRONTEND_RADIO_CHANGE:
+			m_sQueueSample.m_nSampleIndex = SFX_RADIO_CLICK;
+			break;
 		case SOUND_A0: m_sQueueSample.m_nSampleIndex = SFX_INFO; break;
 		default: continue;
 		}
@@ -4049,12 +4679,12 @@ cAudioManager::ProcessFrontEnd()
 			    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
 		}
 		m_sQueueSample.m_bVolume = 110;
-		m_sQueueSample.m_counter = counter++;
+		m_sQueueSample.m_nCounter = counter++;
 		m_sQueueSample.m_nLoopCount = 1;
-		m_sQueueSample.field_56 = 1;
+		m_sQueueSample.m_bReleasingSoundFlag = true;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.field_16 = 0;
-		m_sQueueSample.m_bIsDistant = true;
+		m_sQueueSample.m_nReleasingVolumeModificator = 0;
+		m_sQueueSample.m_bIs2D = true;
 		m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume;
 		m_sQueueSample.m_nLoopStart = 0;
 		m_sQueueSample.m_nLoopEnd = -1;
@@ -4067,7 +4697,7 @@ cAudioManager::ProcessFrontEnd()
 		AddSampleToRequestedQueue();
 		if(stereo) {
 			++m_sQueueSample.m_nSampleIndex;
-			m_sQueueSample.m_counter = counter++;
+			m_sQueueSample.m_nCounter = counter++;
 			m_sQueueSample.m_bOffset = maxVolume - m_sQueueSample.m_bOffset;
 			AddSampleToRequestedQueue();
 		}
@@ -4086,48 +4716,53 @@ cAudioManager::ProcessGarages()
 
 	static uint8 iSound = 32;
 
-#define LOOP_HELPER                                                                                                    \
-	for(j = 0; j < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_AudioEvents; ++j) {                          \
-		switch(m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[j]) {                           \
-		case SOUND_GARAGE_DOOR_CLOSED:                                                                         \
-		case SOUND_GARAGE_DOOR_OPENED:                                                                         \
-			if(distSquared < 6400.f) {                                                                     \
-				CalculateDistance(distCalculated, distSquared);                                        \
-				m_sQueueSample.m_bVolume = ComputeVolume(60, 80.f, m_sQueueSample.m_fDistance);        \
-				if(m_sQueueSample.m_bVolume) {                                                         \
-					if(CGarages::aGarages[i].m_eGarageType == GARAGE_CRUSHER) {                     \
-						m_sQueueSample.m_nSampleIndex = SFX_COL_CAR_PANEL_2;                   \
-						m_sQueueSample.m_nFrequency = 6735;                                    \
-					} else if(m_asAudioEntities[m_sQueueSample.m_nEntityIndex]                     \
-					              .m_awAudioEvent[j] == 69) {                                      \
-						m_sQueueSample.m_nSampleIndex = SFX_COL_CAR_PANEL_2;                   \
-						m_sQueueSample.m_nFrequency = 22000;                                   \
-					} else {                                                                       \
-						m_sQueueSample.m_nSampleIndex = SFX_COL_GARAGE_DOOR_1;                 \
-						m_sQueueSample.m_nFrequency = 18000;                                   \
-					}                                                                              \
-					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;                                 \
-					m_sQueueSample.field_16 = 4;                                                   \
-					m_sQueueSample.m_bEmittingVolume = 60;                                         \
-					m_sQueueSample.field_48 = 0.0f;                                                \
-					m_sQueueSample.m_fSoundIntensity = 80.0f;                                      \
-					/*m_sQueueSample.field_16 = 4;*/                                               \
-					m_sQueueSample.m_bReverbFlag = true;                                           \
-					/*m_sQueueSample.m_bReverbFlag = true;*/                                       \
-					m_sQueueSample.m_bIsDistant = false;                                           \
-					m_sQueueSample.field_56 = 1;                                                   \
-					m_sQueueSample.m_nLoopCount = 1;                                               \
-					m_sQueueSample.m_nLoopStart = 0;                                               \
-					m_sQueueSample.m_nLoopEnd = -1;                                                \
-					m_sQueueSample.m_counter = iSound++;                                           \
-					if(iSound < 32) iSound = 32;                                                   \
-					m_sQueueSample.m_bRequireReflection = true;                                    \
-					AddSampleToRequestedQueue();                                                   \
-				}                                                                                      \
-			}                                                                                              \
-			break;                                                                                         \
-		default: continue;                                                                                     \
-		}                                                                                                      \
+#define LOOP_HELPER                                                                                \
+	for(j = 0; j < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_AudioEvents; ++j) {      \
+		switch(m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[j]) {       \
+		case SOUND_GARAGE_DOOR_CLOSED:                                                     \
+		case SOUND_GARAGE_DOOR_OPENED:                                                     \
+			if(distSquared < 6400.f) {                                                 \
+				CalculateDistance(distCalculated, distSquared);                    \
+				m_sQueueSample.m_bVolume =                                         \
+				    ComputeVolume(60, 80.f, m_sQueueSample.m_fDistance);           \
+				if(m_sQueueSample.m_bVolume) {                                     \
+					if(CGarages::aGarages[i].m_eGarageType ==                  \
+					   GARAGE_CRUSHER) {                                       \
+						m_sQueueSample.m_nSampleIndex =                    \
+						    SFX_COL_CAR_PANEL_2;                           \
+						m_sQueueSample.m_nFrequency = 6735;                \
+					} else if(m_asAudioEntities[m_sQueueSample.m_nEntityIndex] \
+					              .m_awAudioEvent[j] == 69) {                  \
+						m_sQueueSample.m_nSampleIndex =                    \
+						    SFX_COL_CAR_PANEL_2;                           \
+						m_sQueueSample.m_nFrequency = 22000;               \
+					} else {                                                   \
+						m_sQueueSample.m_nSampleIndex =                    \
+						    SFX_COL_GARAGE_DOOR_1;                         \
+						m_sQueueSample.m_nFrequency = 18000;               \
+					}                                                          \
+					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;             \
+					m_sQueueSample.m_nReleasingVolumeModificator = 4;          \
+					m_sQueueSample.m_bEmittingVolume = 60;                     \
+					m_sQueueSample.m_fSpeedMultiplier = 0.0f;                  \
+					m_sQueueSample.m_fSoundIntensity = 80.0f;                  \
+					/*m_sQueueSample.m_nReleasingVolumeModificator = 4;*/      \
+					m_sQueueSample.m_bReverbFlag = true;                       \
+					/*m_sQueueSample.m_bReverbFlag = true;*/                   \
+					m_sQueueSample.m_bIs2D = false;                            \
+					m_sQueueSample.m_bReleasingSoundFlag = true;               \
+					m_sQueueSample.m_nLoopCount = 1;                           \
+					m_sQueueSample.m_nLoopStart = 0;                           \
+					m_sQueueSample.m_nLoopEnd = -1;                            \
+					m_sQueueSample.m_nCounter = iSound++;                      \
+					if(iSound < 32) iSound = 32;                               \
+					m_sQueueSample.m_bRequireReflection = true;                \
+					AddSampleToRequestedQueue();                               \
+				}                                                                  \
+			}                                                                          \
+			break;                                                                     \
+		default: continue;                                                                 \
+		}                                                                                  \
 	}
 
 	for(uint32 i = 0; i < CGarages::NumGarages; ++i) {
@@ -4141,19 +4776,24 @@ cAudioManager::ProcessGarages()
 			state = CGarages::aGarages[i].m_eGarageState;
 			if(state == GS_OPENING || state == GS_CLOSING || state == GS_AFTERDROPOFF) {
 				CalculateDistance(distCalculated, distSquared);
-				m_sQueueSample.m_bVolume = ComputeVolume(90, 80.f, m_sQueueSample.m_fDistance);
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(90, 80.f, m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
 					if(CGarages::aGarages[i].m_eGarageType == GARAGE_CRUSHER) {
-						if(CGarages::aGarages[i].m_eGarageState == GS_AFTERDROPOFF) {
+						if(CGarages::aGarages[i].m_eGarageState ==
+						   GS_AFTERDROPOFF) {
 							if(!(m_FrameCounter & 1)) {
 								LOOP_HELPER
 								continue;
 							}
 							if(m_anRandomTable[1] & 1) {
-								sampleIndex = m_anRandomTable[2] % 5 + SFX_COL_CAR_1;
+								sampleIndex =
+								    m_anRandomTable[2] % 5 +
+								    SFX_COL_CAR_1;
 							} else {
 								sampleIndex =
-								    m_anRandomTable[2] % 6 + SFX_COL_CAR_PANEL_1;
+								    m_anRandomTable[2] % 6 +
+								    SFX_COL_CAR_PANEL_1;
 							}
 							m_sQueueSample.m_nSampleIndex = sampleIndex;
 							m_sQueueSample.m_nFrequency =
@@ -4161,14 +4801,17 @@ cAudioManager::ProcessGarages()
 							        m_sQueueSample.m_nSampleIndex) >>
 							    1;
 							m_sQueueSample.m_nFrequency +=
-							    RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+							    RandomDisplacement(
+							        m_sQueueSample.m_nFrequency >> 4);
 							m_sQueueSample.m_nLoopCount = 1;
-							m_sQueueSample.field_56 = 1;
-							m_sQueueSample.m_counter = iSound++;
+							m_sQueueSample.m_bReleasingSoundFlag = true;
+							m_sQueueSample.m_nCounter = iSound++;
 							if(iSound < 32) iSound = 32;
-							m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-							m_sQueueSample.m_bIsDistant = false;
-							m_sQueueSample.field_16 = 3;
+							m_sQueueSample.m_bBankIndex =
+							    SAMPLEBANK_MAIN;
+							m_sQueueSample.m_bIs2D = false;
+							m_sQueueSample
+							    .m_nReleasingVolumeModificator = 3;
 							m_sQueueSample.m_bEmittingVolume = 90;
 							m_sQueueSample.m_nLoopStart =
 							    SampleManager.GetSampleLoopStartOffset(
@@ -4176,7 +4819,7 @@ cAudioManager::ProcessGarages()
 							m_sQueueSample.m_nLoopEnd =
 							    SampleManager.GetSampleLoopEndOffset(
 							        m_sQueueSample.m_nSampleIndex);
-							m_sQueueSample.field_48 = 2.0f;
+							m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 							m_sQueueSample.m_fSoundIntensity = 80.0f;
 							m_sQueueSample.m_bReverbFlag = true;
 							m_sQueueSample.m_bRequireReflection = false;
@@ -4184,25 +4827,29 @@ cAudioManager::ProcessGarages()
 							LOOP_HELPER
 							continue;
 						}
-						m_sQueueSample.m_nSampleIndex = SFX_FISHING_BOAT_IDLE;
+						m_sQueueSample.m_nSampleIndex =
+						    SFX_FISHING_BOAT_IDLE;
 						m_sQueueSample.m_nFrequency = 6543;
 					} else {
-						m_sQueueSample.m_nSampleIndex = SFX_GARAGE_DOOR_LOOP;
+						m_sQueueSample.m_nSampleIndex =
+						    SFX_GARAGE_DOOR_LOOP;
 						m_sQueueSample.m_nFrequency = 13961;
 					}
-					m_sQueueSample.m_counter = i;
+					m_sQueueSample.m_nCounter = i;
 					m_sQueueSample.m_nLoopCount = 0;
-					m_sQueueSample.field_76 = 3;
-					m_sQueueSample.field_56 = 0;
+					m_sQueueSample.m_nReleasingVolumeDivider = 3;
+					m_sQueueSample.m_bReleasingSoundFlag = false;
 					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-					m_sQueueSample.m_bIsDistant = false;
-					m_sQueueSample.field_16 = 3;
+					m_sQueueSample.m_bIs2D = false;
+					m_sQueueSample.m_nReleasingVolumeModificator = 3;
 					m_sQueueSample.m_bEmittingVolume = 90;
 					m_sQueueSample.m_nLoopStart =
-					    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopStartOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_nLoopEnd =
-					    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-					m_sQueueSample.field_48 = 2.0f;
+					    SampleManager.GetSampleLoopEndOffset(
+					        m_sQueueSample.m_nSampleIndex);
+					m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 					m_sQueueSample.m_fSoundIntensity = 80.0f;
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bRequireReflection = false;
@@ -4232,7 +4879,9 @@ cAudioManager::ProcessHelicopter(cVehicleParams *params)
 	static const tHelicopterSampleData gHeliSfxRanges[3] = {
 	    {400.f, 380.f, 100}, {100.f, 70.f, maxVolume}, {60.f, 30.f, maxVolume}};
 
-	if(gHeliSfxRanges[0].m_fMaxDistance * gHeliSfxRanges[0].m_fMaxDistance <= params->m_fDistance) return false;
+	if(gHeliSfxRanges[0].m_fMaxDistance * gHeliSfxRanges[0].m_fMaxDistance <=
+	   params->m_fDistance)
+		return false;
 
 	CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 	heli = (CHeli *)params->m_pVehicle;
@@ -4242,29 +4891,32 @@ cAudioManager::ProcessHelicopter(cVehicleParams *params)
 		if(dist >= MaxDist) return true;
 		baseDist = gHeliSfxRanges[i].m_fBaseDistance;
 		if(dist < baseDist)
-			emittingVol = (gHeliSfxRanges[i].m_bBaseVolume * ((MaxDist - dist) / (MaxDist - baseDist)));
+			emittingVol = (gHeliSfxRanges[i].m_bBaseVolume *
+			               ((MaxDist - dist) / (MaxDist - baseDist)));
 		else
 			emittingVol = gHeliSfxRanges[i].m_bBaseVolume;
 
-		m_sQueueSample.m_bVolume =
-		    ComputeVolume(emittingVol, gHeliSfxRanges[i].m_fMaxDistance, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume = ComputeVolume(
+		    emittingVol, gHeliSfxRanges[i].m_fMaxDistance, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = i + 65;
+			m_sQueueSample.m_nCounter = i + 65;
 			m_sQueueSample.m_nSampleIndex = i + SFX_HELI_1;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 0;
-			m_sQueueSample.m_nFrequency = 1200 * heli->m_nHeliId + SampleManager.GetSampleBaseFrequency(
-			                                                           m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 0;
+			m_sQueueSample.m_nFrequency =
+			    1200 * heli->m_nHeliId +
+			    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 6.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 			m_sQueueSample.m_fSoundIntensity = gHeliSfxRanges[i].m_fMaxDistance;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 3;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -4297,20 +4949,21 @@ cAudioManager::ProcessHomeScriptObject(uint8 sound)
 		if(dist < SQR(m_sQueueSample.m_fSoundIntensity)) {
 			m_sQueueSample.m_fDistance = Sqrt(dist);
 			rand = m_anRandomTable[0] % 30 + 40;
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    rand, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
 				m_sQueueSample.m_nSampleIndex = m_anRandomTable[0] % 5 + SFX_HOME_1;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 16);
-				m_sQueueSample.m_counter = counter++;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency / 16);
+				m_sQueueSample.m_nCounter = counter++;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_bEmittingVolume = rand;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
@@ -4370,7 +5023,8 @@ cAudioManager::ProcessJumboAccel(CPlane *plane)
 	if(SetupJumboFlySound(20)) {
 		modificator = (plane->m_fSpeed - 0.10334f) * 1.676f;
 		if(modificator > 1.0f) modificator = 1.0f;
-		if(SetupJumboRumbleSound(maxVolume * modificator) && SetupJumboTaxiSound((1.0f - modificator) * 75.f)) {
+		if(SetupJumboRumbleSound(maxVolume * modificator) &&
+		   SetupJumboTaxiSound((1.0f - modificator) * 75.f)) {
 			if(modificator < 0.2f) {
 				whineSoundFreq = modificator * 5.f * 14600.0f + 29500;
 				vol = modificator * 5.f * maxVolume;
@@ -4409,7 +5063,8 @@ cAudioManager::ProcessJumboLanding(CPlane *plane)
 	if(SetupJumboFlySound(107.f * modificator + 20)) {
 		if(SetupJumboTaxiSound(75.f * (1.f - modificator))) {
 			SetupJumboEngineSound(maxVolume, 22050);
-			SetupJumboWhineSound(18.f * (1.f - modificator), 14600.f * modificator + 29500);
+			SetupJumboWhineSound(18.f * (1.f - modificator),
+			                     14600.f * modificator + 29500);
 		}
 	}
 }
@@ -4419,8 +5074,10 @@ cAudioManager::ProcessJumboTakeOff(CPlane *plane)
 {
 	const float modificator = (PlanePathPosition[plane->m_nPlaneId] - TakeOffPoint) / 300.f;
 
-	if(SetupJumboFlySound((107.f * modificator) + 20) && SetupJumboRumbleSound(maxVolume * (1.f - modificator))) {
-		if(SetupJumboEngineSound(maxVolume, 22050)) SetupJumboWhineSound(18.f * (1.f - modificator), 44100);
+	if(SetupJumboFlySound((107.f * modificator) + 20) &&
+	   SetupJumboRumbleSound(maxVolume * (1.f - modificator))) {
+		if(SetupJumboEngineSound(maxVolume, 22050))
+			SetupJumboWhineSound(18.f * (1.f - modificator), 44100);
 	}
 }
 
@@ -4437,9 +5094,7 @@ cAudioManager::ProcessLaunderetteScriptObject(uint8 sound)
 {
 	switch(sound) {
 	case SCRIPT_SOUND_LAUNDERETTE_LOOP_S:
-	case SCRIPT_SOUND_LAUNDERETTE_LOOP_L:
-		m_sQueueSample.m_fSoundIntensity = 30.0f;
-		break;
+	case SCRIPT_SOUND_LAUNDERETTE_LOOP_L: m_sQueueSample.m_fSoundIntensity = 30.0f; break;
 	default: return;
 	}
 	float distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
@@ -4450,37 +5105,41 @@ cAudioManager::ProcessLaunderetteScriptObject(uint8 sound)
 		if(m_sQueueSample.m_bVolume) {
 			m_sQueueSample.m_nSampleIndex = SFX_LAUNDERETTE_LOOP;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_LAUNDERETTE_LOOP);
-			m_sQueueSample.m_counter = 0;
-			m_sQueueSample.m_bIsDistant = false;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_LAUNDERETTE_LOOP);
+			m_sQueueSample.m_nCounter = 0;
+			m_sQueueSample.m_bIs2D = false;
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_16 = 5;
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_bEmittingVolume = 45;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
 		}
-		m_sQueueSample.m_bVolume =
-		    ComputeVolume(110, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume = ComputeVolume(110, m_sQueueSample.m_fSoundIntensity,
+		                                         m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
 			m_sQueueSample.m_nSampleIndex = SFX_LAUNDERETTE_SONG_LOOP;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_LAUNDERETTE_SONG_LOOP);
-			m_sQueueSample.m_counter = 1;
-			m_sQueueSample.m_bIsDistant = false;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_LAUNDERETTE_SONG_LOOP);
+			m_sQueueSample.m_nCounter = 1;
+			m_sQueueSample.m_bIs2D = false;
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_bEmittingVolume = 110;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -4501,9 +5160,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_1_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4511,9 +5170,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_2_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4521,9 +5180,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_2);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_2_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4531,9 +5190,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_2);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_3_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4541,9 +5200,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_3);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_3_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4551,9 +5210,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_3);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_4_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4561,9 +5220,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_4);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_4_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4571,9 +5230,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_4);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_5_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4581,9 +5240,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_5);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_5_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4591,9 +5250,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_5);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_6_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4601,9 +5260,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_6);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_6_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4611,9 +5270,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_6);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_7_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4621,9 +5280,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_7);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_7_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4631,9 +5290,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_7);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_8_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4641,9 +5300,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_8);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_8_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4651,9 +5310,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_8);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_9_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4661,9 +5320,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_9);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_9_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4671,9 +5330,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_9);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_10_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4681,9 +5340,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_10);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_10_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4691,9 +5350,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_10);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_11_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4701,9 +5360,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_11);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_11_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4711,9 +5370,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_11);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_12_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4721,9 +5380,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_12);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_12_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4731,9 +5390,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_12);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_13_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
@@ -4741,9 +5400,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_RAGGA);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_13_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4751,49 +5410,53 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_RAGGA);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_STRIP_CLUB_LOOP_1_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_STRIP_CLUB_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_STRIP_CLUB_LOOP_1_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_STRIP_CLUB_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_STRIP_CLUB_LOOP_2_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_STRIP_CLUB_2;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_2);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_2);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_STRIP_CLUB_LOOP_2_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_STRIP_CLUB_2;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_2);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_STRIP_CLUB_2);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_WORK_SHOP_LOOP_S:
 	case SCRIPT_SOUND_WORK_SHOP_LOOP_L: ProcessWorkShopScriptObject(sound); return;
@@ -4804,20 +5467,22 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = SFX_DOG_FOOD_FACTORY;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_DOG_FOOD_FACTORY);
-		m_sQueueSample.field_16 = 6;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_DOG_FOOD_FACTORY);
+		m_sQueueSample.m_nReleasingVolumeModificator = 6;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_39:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_DOG_FOOD_FACTORY;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_DOG_FOOD_FACTORY);
-		m_sQueueSample.field_16 = 6;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_DOG_FOOD_FACTORY);
+		m_sQueueSample.m_nReleasingVolumeModificator = 6;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_LAUNDERETTE_LOOP_S:
 	case SCRIPT_SOUND_LAUNDERETTE_LOOP_L: ProcessLaunderetteScriptObject(sound); return;
@@ -4826,80 +5491,88 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_CHINATOWN;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_CHINATOWN);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_CHINATOWN);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_CHINATOWN_RESTAURANT_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_CHINATOWN;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_CHINATOWN);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_CHINATOWN);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_CIPRIANI_RESAURANT_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_ITALY;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_ITALY);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_ITALY);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_CIPRIANI_RESAURANT_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_ITALY;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_ITALY);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_ITALY);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_46_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_GENERIC_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_47_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_GENERIC_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_MARCO_BISTRO_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_GENERIC_2;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_2);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_2);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_MARCO_BISTRO_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RESTAURANT_GENERIC_2;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 110;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_2);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RESTAURANT_GENERIC_2);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_AIRPORT_LOOP_S:
 	case SCRIPT_SOUND_AIRPORT_LOOP_L: ProcessAirportScriptObject(sound); return;
@@ -4917,9 +5590,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_PIANO_BAR_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PARTY_1_LOOP:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -4927,9 +5600,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CLUB_1);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PORN_CINEMA_1_S:
 	case SCRIPT_SOUND_PORN_CINEMA_1_L:
@@ -4944,73 +5617,82 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = SFX_BANK_ALARM_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 90;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_BANK_ALARM_1);
-		m_sQueueSample.field_16 = 2;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_BANK_ALARM_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 2;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_BANK_ALARM_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_BANK_ALARM_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 90;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_BANK_ALARM_1);
-		m_sQueueSample.field_16 = 2;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_BANK_ALARM_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 2;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_POLICE_BALL_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_POLICE_BALL_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_POLICE_BALL_1);
-		m_sQueueSample.field_16 = 2;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_POLICE_BALL_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 2;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_POLICE_BALL_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_POLICE_BALL_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_POLICE_BALL_1);
-		m_sQueueSample.field_16 = 2;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_POLICE_BALL_1);
+		m_sQueueSample.m_nReleasingVolumeModificator = 2;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RAVE_INDUSTRIAL;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RAVE_INDUSTRIAL);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RAVE_INDUSTRIAL);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_RAVE_LOOP_INDUSTRIAL_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RAVE_INDUSTRIAL;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RAVE_INDUSTRIAL);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RAVE_INDUSTRIAL);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_S:
-	case SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_L: ProcessPoliceCellBeatingScriptObject(sound); return;
+	case SCRIPT_SOUND_POLICE_CELL_BEATING_LOOP_L:
+		ProcessPoliceCellBeatingScriptObject(sound);
+		return;
 	case SCRIPT_SOUND_RAVE_1_LOOP_S:
 	case SCRIPT_SOUND_RAVE_2_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RAVE_COMMERCIAL;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_RAVE_1_LOOP_L:
 	case SCRIPT_SOUND_RAVE_2_LOOP_L:
@@ -5018,30 +5700,33 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = SFX_RAVE_COMMERCIAL;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_RAVE_3_LOOP_S:
 		m_sQueueSample.m_fSoundIntensity = 30.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RAVE_SUBURBAN;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RAVE_SUBURBAN);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RAVE_SUBURBAN);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_RAVE_3_LOOP_L:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_RAVE_SUBURBAN;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RAVE_SUBURBAN);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_76 = 3;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_RAVE_SUBURBAN);
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_nReleasingVolumeDivider = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	case SCRIPT_SOUND_PRETEND_FIRE_LOOP:
 		m_sQueueSample.m_fSoundIntensity = 50.0f;
@@ -5049,9 +5734,9 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 80;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE);
-		m_sQueueSample.field_16 = 8;
-		m_sQueueSample.field_76 = 10;
-		m_sQueueSample.field_48 = 2.0f;
+		m_sQueueSample.m_nReleasingVolumeModificator = 8;
+		m_sQueueSample.m_nReleasingVolumeDivider = 10;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 		break;
 	default: return;
 	}
@@ -5059,18 +5744,19 @@ cAudioManager::ProcessLoopingScriptObject(uint8 sound)
 	distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 	if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 		m_sQueueSample.m_fDistance = Sqrt(distSquared);
-		m_sQueueSample.m_bVolume =
-		    ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume = ComputeVolume(
+		    emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 0;
-			m_sQueueSample.m_bIsDistant = false;
+			m_sQueueSample.m_nCounter = 0;
+			m_sQueueSample.m_bIs2D = false;
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_56 = 0;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bEmittingVolume = emittingVolume;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
 		}
@@ -5093,12 +5779,13 @@ cAudioManager::ProcessMissionAudio()
 	if(m_bIsInitialised) {
 		if(m_sMissionAudio.m_nSampleIndex != NO_SAMPLE) {
 			switch(m_sMissionAudio.m_bLoadingStatus) {
-			case 0:
-				SampleManager.PreloadStreamedFile(m_sMissionAudio.m_nSampleIndex, 1);
-				m_sMissionAudio.m_bLoadingStatus = 1;
+			case LOADING_STATUS_NOT_LOADED:
+				SampleManager.PreloadStreamedFile(m_sMissionAudio.m_nSampleIndex,
+				                                  1);
+				m_sMissionAudio.m_bLoadingStatus = LOADING_STATUS_LOADED;
 				nFramesUntilFailedLoad = 0;
 				return;
-			case 1:
+			case LOADING_STATUS_LOADED:
 				if(!m_sMissionAudio.m_bIsPlayed) return;
 				if(g_bMissionAudioLoadFailed) {
 					if(m_bTimerJustReset) {
@@ -5109,15 +5796,19 @@ cAudioManager::ProcessMissionAudio()
 						nFramesUntilFailedLoad = 0;
 					} else if(!m_bUserPause) {
 						if(++nFramesForPretendPlaying < 120) {
-							m_sMissionAudio.m_bPlayStatus = 1;
+							m_sMissionAudio.m_bPlayStatus =
+							    PLAY_STATUS_PLAYING;
 						} else {
-							m_sMissionAudio.m_bPlayStatus = 2;
+							m_sMissionAudio.m_bPlayStatus =
+							    PLAY_STATUS_FINISHED;
 							m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
 						}
 					}
 				} else {
 					if(m_sMissionAudio.m_bPlayStatus) {
-						if(m_sMissionAudio.m_bPlayStatus != 1) return;
+						if(m_sMissionAudio.m_bPlayStatus !=
+						   PLAY_STATUS_PLAYING)
+							return;
 						if(m_bTimerJustReset) {
 							ClearMissionAudio();
 							SampleManager.StopStreamedFile(1);
@@ -5128,32 +5819,49 @@ cAudioManager::ProcessMissionAudio()
 							if(!m_bUserPause) {
 								if(nCheckPlayingDelay) {
 									--nCheckPlayingDelay;
-								} else if(GetMissionScriptPoliceAudioPlayingStatus() ==
-								              2 ||
-								          m_sMissionAudio.field_24-- == 0) {
-									m_sMissionAudio.m_bPlayStatus = 2;
-									m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
-									SampleManager.StopStreamedFile(1);
-									m_sMissionAudio.field_24 = 0;
+								} else if(
+								    GetMissionScriptPoliceAudioPlayingStatus() ==
+								        PLAY_STATUS_FINISHED ||
+								    m_sMissionAudio
+								            .m_nMissionAudioCounter-- ==
+								        0) {
+									m_sMissionAudio
+									    .m_bPlayStatus =
+									    PLAY_STATUS_FINISHED;
+									m_sMissionAudio
+									    .m_nSampleIndex =
+									    NO_SAMPLE;
+									SampleManager
+									    .StopStreamedFile(1);
+									m_sMissionAudio
+									    .m_nMissionAudioCounter =
+									    0;
 								}
 							}
 						} else if(m_sMissionAudio.field_22) {
-							if(SampleManager.IsStreamPlaying(1) || m_bUserPause ||
-							   m_bPreviousUserPause) {
+							if(SampleManager.IsStreamPlaying(1) ||
+							   m_bUserPause || m_bPreviousUserPause) {
 								if(m_bUserPause)
-									SampleManager.PauseStream(1, 1);
+									SampleManager.PauseStream(
+									    1, 1);
 								else
-									SampleManager.PauseStream(0, 1);
+									SampleManager.PauseStream(
+									    0, 1);
 							} else {
-								m_sMissionAudio.m_bPlayStatus = 2;
-								m_sMissionAudio.m_nSampleIndex = NO_SAMPLE;
+								m_sMissionAudio.m_bPlayStatus =
+								    PLAY_STATUS_FINISHED;
+								m_sMissionAudio.m_nSampleIndex =
+								    NO_SAMPLE;
 								SampleManager.StopStreamedFile(1);
-								m_sMissionAudio.field_24 = 0;
+								m_sMissionAudio
+								    .m_nMissionAudioCounter = 0;
 							}
 						} else {
 							if(m_bUserPause) return;
 							if(nCheckPlayingDelay--) {
-								if(!SampleManager.IsStreamPlaying(1)) return;
+								if(!SampleManager.IsStreamPlaying(
+								       1))
+									return;
 								nCheckPlayingDelay = 0;
 							}
 							m_sMissionAudio.field_22 = 1;
@@ -5161,30 +5869,40 @@ cAudioManager::ProcessMissionAudio()
 					} else {
 						if(MissionScriptAudioUsesPoliceChannel(
 						       m_sMissionAudio.m_nSampleIndex)) {
-							SetMissionScriptPoliceAudio(m_sMissionAudio.m_nSampleIndex);
+							SetMissionScriptPoliceAudio(
+							    m_sMissionAudio.m_nSampleIndex);
 						} else {
-							if(m_bUserPause) SampleManager.PauseStream(1, 1);
-							if(m_sMissionAudio.field_12) {
-								SampleManager.SetStreamedVolumeAndPan(80, 63, 1, 1);
+							if(m_bUserPause)
+								SampleManager.PauseStream(1, 1);
+							if(m_sMissionAudio
+							       .m_bPredefinedProperties) {
+								SampleManager
+								    .SetStreamedVolumeAndPan(80, 63,
+								                             1, 1);
 							} else {
-								distSquared =
-								    GetDistanceSquared(&m_sMissionAudio.m_vecPos);
+								distSquared = GetDistanceSquared(
+								    &m_sMissionAudio.m_vecPos);
 								if(distSquared >= 2500.f) {
 									emittingVol = 0;
 									pan = 63;
 								} else {
 									dist = Sqrt(distSquared);
-									emittingVol = ComputeVolume(80, 50.0f, dist);
-									TranslateEntity(&m_sMissionAudio.m_vecPos,
-									                &vec);
-									pan = ComputePan(50.f, &vec);
+									emittingVol = ComputeVolume(
+									    80, 50.0f, dist);
+									TranslateEntity(
+									    &m_sMissionAudio
+									         .m_vecPos,
+									    &vec);
+									pan =
+									    ComputePan(50.f, &vec);
 								}
-								SampleManager.SetStreamedVolumeAndPan(emittingVol, pan,
-								                                      1, 1);
+								SampleManager
+								    .SetStreamedVolumeAndPan(
+								        emittingVol, pan, 1, 1);
 							}
 							SampleManager.StartPreloadedStreamedFile(1);
 						}
-						m_sMissionAudio.m_bPlayStatus = 1;
+						m_sMissionAudio.m_bPlayStatus = PLAY_STATUS_PLAYING;
 						nCheckPlayingDelay = 30;
 					}
 				}
@@ -5192,9 +5910,9 @@ cAudioManager::ProcessMissionAudio()
 			case 2:
 				if(++nFramesUntilFailedLoad >= 90) {
 					nFramesForPretendPlaying = 0;
-					g_bMissionAudioLoadFailed = 1;
+					g_bMissionAudioLoadFailed = true;
 					nFramesUntilFailedLoad = 0;
-					m_sMissionAudio.m_bLoadingStatus = 1;
+					m_sMissionAudio.m_bLoadingStatus = LOADING_STATUS_LOADED;
 				}
 				return;
 			default: return;
@@ -5218,8 +5936,10 @@ cAudioManager::ProcessModelCarEngine(cVehicleParams *params)
 				velocityChange = Abs(params->m_fVelocityChange);
 			} else {
 				if(automobile->m_nDriveWheelsOnGround)
-					automobile->m_fGasPedalAudio = automobile->m_fGasPedalAudio * 0.4f;
-				velocityChange = automobile->m_fGasPedalAudio * params->m_pTransmission->fMaxVelocity;
+					automobile->m_fGasPedalAudio =
+					    automobile->m_fGasPedalAudio * 0.4f;
+				velocityChange = automobile->m_fGasPedalAudio *
+				                 params->m_pTransmission->fMaxVelocity;
 			}
 			if(velocityChange > 0.001f) {
 				allowedVelocity = 0.5f * params->m_pTransmission->fMaxVelocity;
@@ -5228,28 +5948,33 @@ cAudioManager::ProcessModelCarEngine(cVehicleParams *params)
 				else
 					emittingVol = 90;
 				if(emittingVol) {
-					CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
-					m_sQueueSample.m_bVolume =
-					    ComputeVolume(emittingVol, 30.f, m_sQueueSample.m_fDistance);
+					CalculateDistance(params->m_bDistanceCalculated,
+					                  params->m_fDistance);
+					m_sQueueSample.m_bVolume = ComputeVolume(
+					    emittingVol, 30.f, m_sQueueSample.m_fDistance);
 					if(m_sQueueSample.m_bVolume) {
-						m_sQueueSample.m_counter = 2;
-						m_sQueueSample.m_nSampleIndex = SFX_REMOTE_CONTROLLED_CAR;
+						m_sQueueSample.m_nCounter = 2;
+						m_sQueueSample.m_nSampleIndex =
+						    SFX_REMOTE_CONTROLLED_CAR;
 						m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-						m_sQueueSample.m_bIsDistant = false;
-						m_sQueueSample.field_16 = 1;
+						m_sQueueSample.m_bIs2D = false;
+						m_sQueueSample.m_nReleasingVolumeModificator = 1;
 						m_sQueueSample.m_nFrequency =
-						    (11025.f * velocityChange / params->m_pTransmission->fMaxVelocity +
+						    (11025.f * velocityChange /
+						         params->m_pTransmission->fMaxVelocity +
 						     11025.f);
 						m_sQueueSample.m_nLoopCount = 0;
 						m_sQueueSample.m_bEmittingVolume = emittingVol;
-						m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(
-						    m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_nLoopStart =
+						    SampleManager.GetSampleLoopStartOffset(
+						        m_sQueueSample.m_nSampleIndex);
 						m_sQueueSample.m_nLoopEnd =
-						    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-						m_sQueueSample.field_48 = 3.0f;
+						    SampleManager.GetSampleLoopEndOffset(
+						        m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_fSpeedMultiplier = 3.0f;
 						m_sQueueSample.m_fSoundIntensity = 30.0f;
-						m_sQueueSample.field_56 = 0;
-						m_sQueueSample.field_76 = 3;
+						m_sQueueSample.m_bReleasingSoundFlag = false;
+						m_sQueueSample.m_nReleasingVolumeDivider = 3;
 						m_sQueueSample.m_bReverbFlag = true;
 						m_sQueueSample.m_bRequireReflection = false;
 						AddSampleToRequestedQueue();
@@ -5296,9 +6021,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 			m_sQueueSample.m_nFrequency = 10600;
 		else
 			m_sQueueSample.m_nFrequency = 9000;
-		m_sQueueSample.field_16 = 1;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 1;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		m_sQueueSample.m_bRequireReflection = true;
 		emittingVolume = RandomDisplacement(10) + 50;
 		break;
@@ -5308,11 +6033,12 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_fSoundIntensity = 50.0f;
 		m_sQueueSample.m_nSampleIndex = m_anRandomTable[iSound % 5] % 3 + SFX_BULLET_WALL_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
 		m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-		m_sQueueSample.field_16 = 9;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 9;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		emittingVolume = m_anRandomTable[2] % 20 + 90;
 		break;
 	case SCRIPT_SOUND_110:
@@ -5322,10 +6048,11 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = SFX_TRAIN_STATION_ANNOUNCE;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = maxVolume;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_TRAIN_STATION_ANNOUNCE);
-		m_sQueueSample.field_16 = 0;
-		m_sQueueSample.field_48 = 2.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_TRAIN_STATION_ANNOUNCE);
+		m_sQueueSample.m_nReleasingVolumeModificator = 0;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+		m_sQueueSample.m_bIs2D = false;
 		break;
 	case SCRIPT_SOUND_PAYPHONE_RINGING:
 		m_sQueueSample.m_fSoundIntensity = 80.0f;
@@ -5333,9 +6060,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 80;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_PHONE_RING);
-		m_sQueueSample.field_16 = 1;
-		m_sQueueSample.field_48 = 2.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 1;
+		m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+		m_sQueueSample.m_bIs2D = false;
 		m_sQueueSample.m_bRequireReflection = false;
 		break;
 	case SCRIPT_SOUND_GLASS_BREAK_L:
@@ -5344,9 +6071,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 70;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_GLASS_SMASH);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		break;
 	case SCRIPT_SOUND_GLASS_BREAK_S:
 		m_sQueueSample.m_fSoundIntensity = 60.0f;
@@ -5354,9 +6081,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 60;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_GLASS_SMASH);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		break;
 	case SCRIPT_SOUND_GLASS_CRACK:
 		m_sQueueSample.m_fSoundIntensity = 60.0f;
@@ -5364,9 +6091,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		emittingVolume = 70;
 		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_GLASS_CRACK);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		m_sQueueSample.m_bRequireReflection = true;
 		break;
 	case SCRIPT_SOUND_GLASS_LIGHT_BREAK:
@@ -5374,9 +6101,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = (m_anRandomTable[4] & 3) + SFX_GLASS_SHARD_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		m_sQueueSample.m_nFrequency = RandomDisplacement(2000) + 19000;
-		m_sQueueSample.field_16 = 9;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 9;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		emittingVolume = RandomDisplacement(11) + 25;
 		break;
 	case SCRIPT_SOUND_BOX_DESTROYED_1:
@@ -5384,9 +6111,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = SFX_WOODEN_BOX_SMASH;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		m_sQueueSample.m_nFrequency = RandomDisplacement(1500) + 18600;
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		m_sQueueSample.m_bRequireReflection = true;
 		emittingVolume = m_anRandomTable[2] % 20 + 80;
 		break;
@@ -5395,9 +6122,9 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_nSampleIndex = SFX_CARDBOARD_BOX_SMASH;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 		m_sQueueSample.m_nFrequency = RandomDisplacement(1500) + 18600;
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		m_sQueueSample.m_bRequireReflection = true;
 		emittingVolume = m_anRandomTable[2] % 20 + 80;
 		break;
@@ -5405,11 +6132,12 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_fSoundIntensity = 60.0f;
 		m_sQueueSample.m_nSampleIndex = m_anRandomTable[3] % 5 + SFX_COL_CAR_1;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
 		m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		m_sQueueSample.m_bRequireReflection = true;
 		emittingVolume = m_anRandomTable[2] % 30 + 70;
 		break;
@@ -5417,11 +6145,12 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		m_sQueueSample.m_fSoundIntensity = 60.0f;
 		m_sQueueSample.m_nSampleIndex = SFX_TYRE_BUMP;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
 		m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
-		m_sQueueSample.field_16 = 3;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 3;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		m_sQueueSample.m_bRequireReflection = true;
 		emittingVolume = m_anRandomTable[2] % 30 + 60;
 		break;
@@ -5439,22 +6168,22 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 			case SURFACE_HEDGE:
 				m_sQueueSample.m_nSampleIndex = SFX_BULLET_SHELL_HIT_GROUND_2;
 				m_sQueueSample.m_nFrequency = RandomDisplacement(500) + 11000;
-				m_sQueueSample.field_16 = 18;
+				m_sQueueSample.m_nReleasingVolumeModificator = 18;
 				m_sQueueSample.m_fSoundIntensity = 20.0f;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+				m_sQueueSample.m_bIs2D = false;
 				emittingVolume = m_anRandomTable[2] % 20 + 30;
 				distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 				if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 					m_sQueueSample.m_fDistance = Sqrt(distSquared);
-					m_sQueueSample.m_bVolume =
-					    ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity,
-					                  m_sQueueSample.m_fDistance);
+					m_sQueueSample.m_bVolume = ComputeVolume(
+					    emittingVolume, m_sQueueSample.m_fSoundIntensity,
+					    m_sQueueSample.m_fDistance);
 					if(m_sQueueSample.m_bVolume) {
-						m_sQueueSample.m_counter = iSound++;
+						m_sQueueSample.m_nCounter = iSound++;
 						m_sQueueSample.m_nLoopCount = 1;
-						m_sQueueSample.field_56 = 1;
+						m_sQueueSample.m_bReleasingSoundFlag = true;
 						m_sQueueSample.m_bEmittingVolume = emittingVolume;
 						m_sQueueSample.m_nLoopStart = 0;
 						m_sQueueSample.m_nLoopEnd = -1;
@@ -5469,21 +6198,21 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 		}
 		m_sQueueSample.m_nSampleIndex = SFX_BULLET_SHELL_HIT_GROUND_1;
 		m_sQueueSample.m_nFrequency = RandomDisplacement(750) + 18000;
-		m_sQueueSample.field_16 = 15;
+		m_sQueueSample.m_nReleasingVolumeModificator = 15;
 		m_sQueueSample.m_fSoundIntensity = 20.0f;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		emittingVolume = m_anRandomTable[2] % 20 + 30;
 		break;
 	case SCRIPT_SOUND_GUNSHELL_DROP_SOFT:
 		m_sQueueSample.m_nSampleIndex = SFX_BULLET_SHELL_HIT_GROUND_2;
 		m_sQueueSample.m_nFrequency = RandomDisplacement(500) + 11000;
-		m_sQueueSample.field_16 = 18;
+		m_sQueueSample.m_nReleasingVolumeModificator = 18;
 		m_sQueueSample.m_fSoundIntensity = 20.0f;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.field_48 = 0.0f;
-		m_sQueueSample.m_bIsDistant = false;
+		m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+		m_sQueueSample.m_bIs2D = false;
 		emittingVolume = m_anRandomTable[2] % 20 + 30;
 		break;
 	default: return;
@@ -5492,12 +6221,12 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound)
 	distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 	if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 		m_sQueueSample.m_fDistance = Sqrt(distSquared);
-		m_sQueueSample.m_bVolume =
-		    ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume = ComputeVolume(
+		    emittingVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = iSound++;
+			m_sQueueSample.m_nCounter = iSound++;
 			m_sQueueSample.m_nLoopCount = 1;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bReleasingSoundFlag = true;
 			m_sQueueSample.m_bEmittingVolume = emittingVolume;
 			m_sQueueSample.m_nLoopStart = 0;
 			m_sQueueSample.m_nLoopEnd = -1;
@@ -5518,7 +6247,7 @@ cAudioManager::ProcessPed(CPhysical *ped)
 
 	m_sQueueSample.m_vecPos = ped->GetPosition();
 
-	//params.m_bDistanceCalculated = false;
+	// params.m_bDistanceCalculated = false;
 	params.m_pPed = (CPed *)ped;
 	params.m_fDistance = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 	if(ped->m_modelIndex == MI_FATMALE02) ProcessPedHeadphones(&params);
@@ -5538,10 +6267,11 @@ cAudioManager::ProcessPedHeadphones(cPedParams *params)
 			CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 			if(ped->bInVehicle && ped->m_nPedState == PED_DRIVING) {
 				emittingVol = 10;
-				veh = (CAutomobile*)ped->m_pMyVehicle;
+				veh = (CAutomobile *)ped->m_pMyVehicle;
 				if(veh && veh->IsCar()) {
 					for(int32 i = 2; i < ARRAYSIZE(veh->Doors); i++) {
-						if(!veh->IsDoorClosed((eDoors)i) || veh->IsDoorMissing((eDoors)i)) {
+						if(!veh->IsDoorClosed((eDoors)i) ||
+						   veh->IsDoorMissing((eDoors)i)) {
 							emittingVol = 42;
 							break;
 						}
@@ -5551,25 +6281,27 @@ cAudioManager::ProcessPedHeadphones(cPedParams *params)
 				emittingVol = 42;
 			}
 
-			m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 7.f, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, 7.f, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_counter = 64;
+				m_sQueueSample.m_nCounter = 64;
 				m_sQueueSample.m_nSampleIndex = SFX_HEADPHONES;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 5;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 5;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_HEADPHONES);
 				m_sQueueSample.m_nLoopCount = 0;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
 				m_sQueueSample.m_nLoopStart =
-				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.field_48 = 4.0f;
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 				m_sQueueSample.m_fSoundIntensity = 7.0f;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_76 = 5;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
+				m_sQueueSample.m_nReleasingVolumeDivider = 5;
 				m_sQueueSample.m_bReverbFlag = true;
 				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
@@ -5579,14 +6311,6 @@ cAudioManager::ProcessPedHeadphones(cPedParams *params)
 	}
 }
 
-#if 1
-WRAPPER
-void
-cAudioManager::ProcessPedOneShots(cPedParams *params)
-{
-	EAXJMP(0x56F650);
-}
-#else
 void
 cAudioManager::ProcessPedOneShots(cPedParams *params)
 {
@@ -5597,15 +6321,15 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 
 	bool stereo;
 	int16 sound;
-	char noReflection;
+	bool noReflection;
 	CWeapon *weapon;
-	float maxDist;
+	float maxDist = 0.f; // uninitialized variable
 
 	static uint8 iSound = 21;
 
-	weapon = nil;
+	weapon = params->m_pPed->GetWeapon();
 	for(uint32 i = 0; i < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_AudioEvents; i++) {
-		noReflection = 0;
+		noReflection = false;
 		stereo = 0;
 		m_sQueueSample.m_bRequireReflection = false;
 		sound = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i];
@@ -5614,7 +6338,8 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 		case SOUND_STEP_END:
 			if(!params->m_pPed->bIsLooking) {
 				emittingVol = m_anRandomTable[3] % 15 + 45;
-				if(FindPlayerPed() != m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity)
+				if(FindPlayerPed() !=
+				   m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity)
 					emittingVol >>= 1;
 				maxDist = 400.f;
 				switch(params->m_pPed->m_nSurfaceTouched) {
@@ -5623,7 +6348,8 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 					break;
 				case SURFACE_DIRT:
 				case SURFACE_DIRTTRACK:
-					sampleIndex = m_anRandomTable[4] % 5 + SFX_FOOTSTEP_GRAVEL_1;
+					sampleIndex =
+					    m_anRandomTable[4] % 5 + SFX_FOOTSTEP_GRAVEL_1;
 					break;
 				case SURFACE_METAL6:
 				case SURFACE_METAL_DOOR:
@@ -5639,10 +6365,12 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 					sampleIndex = m_anRandomTable[0] % 5 + SFX_FOOTSTEP_METAL_1;
 					break;
 				case SURFACE_SAND:
-					sampleIndex = (m_anRandomTable[4] & 3) + SFX_FOOTSTEP_SAND_1;
+					sampleIndex =
+					    (m_anRandomTable[4] & 3) + SFX_FOOTSTEP_SAND_1;
 					break;
 				case SURFACE_PUDDLE:
-					sampleIndex = (m_anRandomTable[3] & 3) + SFX_FOOTSTEP_WATER_1;
+					sampleIndex =
+					    (m_anRandomTable[3] & 3) + SFX_FOOTSTEP_WATER_1;
 					break;
 				case SURFACE_WOOD:
 				case SURFACE_WOOD_BOX:
@@ -5653,37 +6381,46 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 					sampleIndex = m_anRandomTable[2] % 5 + SFX_COL_VEG_1;
 					break;
 				default:
-					sampleIndex = m_anRandomTable[2] % 5 + SFX_FOOTSTEP_CONCRETE_1;
+					sampleIndex =
+					    m_anRandomTable[2] % 5 + SFX_FOOTSTEP_CONCRETE_1;
 					break;
 				}
 				m_sQueueSample.m_nSampleIndex = sampleIndex;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter =
-				    m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] - 28;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 17);
+				m_sQueueSample.m_nCounter =
+				    m_asAudioEntities[m_sQueueSample.m_nEntityIndex]
+				        .m_awAudioEvent[i] -
+				    28;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency / 17);
 				switch(params->m_pPed->m_nMoveState) {
-				case 2:
+				case PEDMOVE_WALK:
 					emittingVol >>= 2;
-					m_sQueueSample.m_nFrequency = 9 * m_sQueueSample.m_nFrequency / 10;
+					m_sQueueSample.m_nFrequency =
+					    9 * m_sQueueSample.m_nFrequency / 10;
 					break;
-				case 3:
+				case PEDMOVE_RUN:
 					emittingVol >>= 1;
-					m_sQueueSample.m_nFrequency = 11 * m_sQueueSample.m_nFrequency / 10;
+					m_sQueueSample.m_nFrequency =
+					    11 * m_sQueueSample.m_nFrequency / 10;
+					break;
+				case PEDMOVE_SPRINT:
+					m_sQueueSample.m_nFrequency =
+					    12 * m_sQueueSample.m_nFrequency / 10;
 					break;
-				case 4: m_sQueueSample.m_nFrequency = 12 * m_sQueueSample.m_nFrequency / 10; break;
 				default: break;
 				}
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nReleasingVolumeModificator = 5;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 20.0f;
 				m_sQueueSample.m_nLoopCount = 1;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				m_sQueueSample.m_bRequireReflection = true;
 			}
 			break;
@@ -5701,32 +6438,32 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 					m_sQueueSample.m_nSampleIndex = SFX_BODY_LAND_AND_FALL;
 				}
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = 1;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 17);
-				m_sQueueSample.field_16 = 2;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nCounter = 1;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency / 17);
+				m_sQueueSample.m_nReleasingVolumeModificator = 2;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 30.0f;
 				m_sQueueSample.m_nLoopCount = 1;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				m_sQueueSample.m_bRequireReflection = true;
-				break;
 			}
 			break;
 		case SOUND_FIGHT_PUNCH_33:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_1;
 			m_sQueueSample.m_nFrequency = 18000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5734,19 +6471,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_KICK_34:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_1;
 			m_sQueueSample.m_nFrequency = 16500;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5754,19 +6491,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_HEADBUTT_35:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_1;
 			m_sQueueSample.m_nFrequency = 20000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5774,19 +6511,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_PUNCH_36:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_2;
 			m_sQueueSample.m_nFrequency = 18000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5794,19 +6531,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_PUNCH_37:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_2;
 			m_sQueueSample.m_nFrequency = 16500;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5814,19 +6551,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_CLOSE_PUNCH_38:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_2;
 			m_sQueueSample.m_nFrequency = 20000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5834,19 +6571,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_PUNCH_39:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_4;
 			m_sQueueSample.m_nFrequency = 18000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5854,19 +6591,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_4;
 			m_sQueueSample.m_nFrequency = 16500;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5874,19 +6611,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_PUNCH_41:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_4;
 			m_sQueueSample.m_nFrequency = 20000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5894,19 +6631,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_PUNCH_FROM_BEHIND_42:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_5;
 			m_sQueueSample.m_nFrequency = 18000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5914,19 +6651,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_KNEE_OR_KICK_43:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_5;
 			m_sQueueSample.m_nFrequency = 16500;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5934,19 +6671,19 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_FIGHT_KICK_44:
 			m_sQueueSample.m_nSampleIndex = SFX_FIGHT_5;
 			m_sQueueSample.m_nFrequency = 20000;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound;
+			m_sQueueSample.m_nCounter = iSound;
 			stereo = 1;
 			++iSound;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5954,18 +6691,18 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[3] % 26 + 100;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_WEAPON_BAT_ATTACK:
 			m_sQueueSample.m_nSampleIndex = SFX_BAT_HIT_LEFT;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound++;
+			m_sQueueSample.m_nCounter = iSound++;
 			stereo = 1;
 			m_sQueueSample.m_nFrequency = RandomDisplacement(2000) + 22000;
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -5973,12 +6710,12 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			m_sQueueSample.m_nLoopEnd = -1;
 			emittingVol = m_anRandomTable[2] % 20 + 100;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			if(m_bDynamicAcousticModelingStatus)
 				m_sQueueSample.m_bRequireReflection = true;
 			else
-				noReflection = 1;
+				noReflection = true;
 			break;
 		case SOUND_WEAPON_SHOT_FIRED:
 			weapon = &ped->m_weapons[ped->m_currentWeapon];
@@ -5986,13 +6723,14 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			case WEAPONTYPE_COLT45:
 				m_sQueueSample.m_nSampleIndex = SFX_COLT45_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = iSound++;
+				m_sQueueSample.m_nCounter = iSound++;
 				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_COLT45_LEFT);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 50.0f;
 				maxDist = SQR(50);
 				m_sQueueSample.m_nLoopCount = 1;
@@ -6000,23 +6738,24 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 				m_sQueueSample.m_nLoopEnd = -1;
 				emittingVol = m_anRandomTable[1] % 10 + 90;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				if(m_bDynamicAcousticModelingStatus)
 					m_sQueueSample.m_bRequireReflection = true;
 				else
-					noReflection = 1;
+					noReflection = true;
 				break;
 			case WEAPONTYPE_UZI:
 				m_sQueueSample.m_nSampleIndex = SFX_UZI_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = iSound++;
+				m_sQueueSample.m_nCounter = iSound++;
 				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_UZI_LEFT);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 80.0f;
 				maxDist = SQR(80);
 				m_sQueueSample.m_nLoopCount = 1;
@@ -6024,19 +6763,20 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 				emittingVol = m_anRandomTable[3] % 15 + 70;
 				m_sQueueSample.m_nLoopEnd = -1;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				break;
 			case WEAPONTYPE_SHOTGUN:
 				m_sQueueSample.m_nSampleIndex = SFX_SHOTGUN_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = iSound++;
+				m_sQueueSample.m_nCounter = iSound++;
 				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_SHOTGUN_LEFT);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 60.0f;
 				maxDist = 3600.f;
 				m_sQueueSample.m_nLoopCount = 1;
@@ -6044,23 +6784,24 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 				m_sQueueSample.m_nLoopEnd = -1;
 				emittingVol = m_anRandomTable[2] % 10 + 100;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				if(m_bDynamicAcousticModelingStatus)
 					m_sQueueSample.m_bRequireReflection = true;
 				else
-					noReflection = 1;
+					noReflection = true;
 				break;
 			case WEAPONTYPE_AK47:
 				m_sQueueSample.m_nSampleIndex = SFX_AK47_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = iSound++;
+				m_sQueueSample.m_nCounter = iSound++;
 				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_AK47_LEFT);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 80.0f;
 				maxDist = SQR(80);
 				m_sQueueSample.m_nLoopCount = 1;
@@ -6068,19 +6809,20 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 				emittingVol = m_anRandomTable[1] % 15 + 70;
 				m_sQueueSample.m_nLoopEnd = -1;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				break;
 			case WEAPONTYPE_M16:
 				m_sQueueSample.m_nSampleIndex = SFX_M16_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = iSound++;
+				m_sQueueSample.m_nCounter = iSound++;
 				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_M16_LEFT);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 80.0f;
 				maxDist = SQR(80);
 				m_sQueueSample.m_nLoopCount = 1;
@@ -6088,19 +6830,20 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 				emittingVol = m_anRandomTable[4] % 15 + 70;
 				m_sQueueSample.m_nLoopEnd = -1;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				break;
 			case WEAPONTYPE_SNIPERRIFLE:
 				m_sQueueSample.m_nSampleIndex = SFX_SNIPER_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = iSound++;
+				m_sQueueSample.m_nCounter = iSound++;
 				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_SNIPER_LEFT);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 60.0f;
 				maxDist = 3600.f;
 				m_sQueueSample.m_nLoopCount = 1;
@@ -6108,23 +6851,24 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 				m_sQueueSample.m_nLoopEnd = -1;
 				emittingVol = m_anRandomTable[4] % 10 + 110;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				if(m_bDynamicAcousticModelingStatus)
 					m_sQueueSample.m_bRequireReflection = true;
 				else
-					noReflection = 1;
+					noReflection = true;
 				break;
 			case WEAPONTYPE_ROCKETLAUNCHER:
 				m_sQueueSample.m_nSampleIndex = SFX_ROCKET_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = iSound++;
+				m_sQueueSample.m_nCounter = iSound++;
 				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_ROCKET_LEFT);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
-				m_sQueueSample.field_16 = 1;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+				m_sQueueSample.m_nReleasingVolumeModificator = 1;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = 90.0f;
 				maxDist = 8100.f;
 				m_sQueueSample.m_nLoopCount = 1;
@@ -6132,38 +6876,39 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 				m_sQueueSample.m_nLoopEnd = -1;
 				emittingVol = m_anRandomTable[0] % 20 + 80;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 1;
 				if(m_bDynamicAcousticModelingStatus)
 					m_sQueueSample.m_bRequireReflection = true;
 				else
-					noReflection = 1;
+					noReflection = true;
 				break;
 			case WEAPONTYPE_FLAMETHROWER:
 				m_sQueueSample.m_nSampleIndex = SFX_FLAMETHROWER_LEFT;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_counter = 9;
+				m_sQueueSample.m_nCounter = 9;
 				emittingVol = 90;
 				m_sQueueSample.m_nFrequency =
 				    (10 * m_sQueueSample.m_nEntityIndex & 2047) +
 				    SampleManager.GetSampleBaseFrequency(SFX_FLAMETHROWER_LEFT);
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 4.0f;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 				m_sQueueSample.m_fSoundIntensity = 60.0f;
 				maxDist = 3600.f;
 				m_sQueueSample.m_nLoopCount = 0;
 				m_sQueueSample.m_nLoopStart =
-				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
 				m_sQueueSample.m_bEmittingVolume = 90;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_76 = 6;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_bReleasingSoundFlag = 0;
+				m_sQueueSample.m_nReleasingVolumeDivider = 6;
 				if(m_bDynamicAcousticModelingStatus)
 					m_sQueueSample.m_bRequireReflection = true;
 				else
-					noReflection = 1;
+					noReflection = true;
 				break;
 			default: continue;
 			}
@@ -6174,164 +6919,70 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			switch(weapon->m_eWeaponType) {
 			case WEAPONTYPE_COLT45:
 				m_sQueueSample.m_nSampleIndex = SFX_PISTOL_RELOAD;
-				emittingVol = 75;
-				m_sQueueSample.m_counter = iSound++;
-				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_PISTOL_RELOAD) +
 				    RandomDisplacement(300);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(300);
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_fSoundIntensity = 30.0f;
-				maxDist = SQR(30);
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.m_bEmittingVolume = 75;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bRequireReflection = true;
 				break;
 			case WEAPONTYPE_UZI:
 				m_sQueueSample.m_nSampleIndex = SFX_M16_RELOAD;
-				emittingVol = 75;
-				m_sQueueSample.m_counter = iSound++;
-				stereo = 1;
 				m_sQueueSample.m_nFrequency = 39243;
-				m_sQueueSample.m_nFrequency += RandomDisplacement(300);
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_fSoundIntensity = 30.0f;
-				maxDist = SQR(30);
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.m_bEmittingVolume = 75;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bRequireReflection = true;
 				break;
 			case WEAPONTYPE_SHOTGUN:
 				m_sQueueSample.m_nSampleIndex = SFX_AK47_RELOAD;
-				emittingVol = 75;
-				m_sQueueSample.m_counter = iSound++;
-				stereo = 1;
 				m_sQueueSample.m_nFrequency = 30290;
-				m_sQueueSample.m_nFrequency += RandomDisplacement(300);
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_fSoundIntensity = 30.0f;
-				maxDist = SQR(30);
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.m_bEmittingVolume = 75;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bRequireReflection = true;
 				break;
 			case WEAPONTYPE_AK47:
 				m_sQueueSample.m_nSampleIndex = SFX_AK47_RELOAD;
-				emittingVol = 75;
-				m_sQueueSample.m_counter = iSound++;
-				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_AK47_RELOAD);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(300);
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_fSoundIntensity = 30.0f;
-				maxDist = SQR(30);
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.m_bEmittingVolume = 75;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bRequireReflection = true;
 				break;
 			case WEAPONTYPE_M16:
 				m_sQueueSample.m_nSampleIndex = SFX_M16_RELOAD;
-				emittingVol = 75;
-				m_sQueueSample.m_counter = iSound++;
-				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_M16_RELOAD);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(300);
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_fSoundIntensity = 30.0f;
-				maxDist = SQR(30);
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.m_bEmittingVolume = 75;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bRequireReflection = true;
 				break;
 			case WEAPONTYPE_SNIPERRIFLE:
 				m_sQueueSample.m_nSampleIndex = SFX_RIFLE_RELOAD;
-				emittingVol = 75;
-				m_sQueueSample.m_counter = iSound++;
-				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_RIFLE_RELOAD);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(300);
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_fSoundIntensity = 30.0f;
-				maxDist = SQR(30);
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.m_bEmittingVolume = 75;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bRequireReflection = true;
 				break;
 			case WEAPONTYPE_ROCKETLAUNCHER:
 				m_sQueueSample.m_nSampleIndex = SFX_ROCKET_RELOAD;
-				emittingVol = 75;
-				m_sQueueSample.m_counter = iSound++;
-				stereo = 1;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_ROCKET_RELOAD);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(300);
-				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.field_16 = 5;
-				m_sQueueSample.field_48 = 0.0f;
-				m_sQueueSample.m_fSoundIntensity = 30.0f;
-				maxDist = SQR(30);
-				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.m_nLoopStart = 0;
-				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.m_bEmittingVolume = 75;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.m_bRequireReflection = true;
 				break;
 			default: continue;
 			}
+			emittingVol = 75;
+			m_sQueueSample.m_nCounter = iSound++;
+			stereo = 1;
+			m_sQueueSample.m_nFrequency += RandomDisplacement(300);
+			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 30.0f;
+			maxDist = SQR(30);
+			m_sQueueSample.m_nLoopCount = 1;
+			m_sQueueSample.m_nLoopStart = 0;
+			m_sQueueSample.m_nLoopEnd = -1;
+			m_sQueueSample.m_bEmittingVolume = 75;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
+			m_sQueueSample.m_bRequireReflection = true;
 			break;
 		case SOUND_WEAPON_AK47_BULLET_ECHO:
 		case SOUND_WEAPON_UZI_BULLET_ECHO:
 		case SOUND_WEAPON_M16_BULLET_ECHO:
 			m_sQueueSample.m_nSampleIndex = SFX_UZI_END_LEFT;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound++;
+			m_sQueueSample.m_nCounter = iSound++;
 			stereo = 1;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_UZI_END_LEFT);
-			m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_UZI_END_LEFT);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 80.0f;
 			maxDist = SQR(80);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -6339,22 +6990,23 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			m_sQueueSample.m_nLoopEnd = -1;
 			emittingVol = m_anRandomTable[4] % 10 + 40;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			if(m_bDynamicAcousticModelingStatus)
 				m_sQueueSample.m_bRequireReflection = true;
 			else
-				noReflection = 1;
+				noReflection = true;
 			break;
 		case SOUND_WEAPON_FLAMETHROWER_FIRE:
 			m_sQueueSample.m_nSampleIndex = SFX_FLAMETHROWER_START_LEFT;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound++;
+			m_sQueueSample.m_nCounter = iSound++;
 			m_sQueueSample.m_nFrequency =
 			    SampleManager.GetSampleBaseFrequency(SFX_FLAMETHROWER_START_LEFT);
-			m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
-			m_sQueueSample.field_16 = 3;
-			m_sQueueSample.field_48 = 4.0f;
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 			m_sQueueSample.m_fSoundIntensity = 60.0f;
 			maxDist = 3600.f;
 			m_sQueueSample.m_nLoopCount = 1;
@@ -6362,18 +7014,20 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			m_sQueueSample.m_nLoopEnd = -1;
 			emittingVol = 70;
 			m_sQueueSample.m_bEmittingVolume = 70;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			break;
 		case SOUND_WEAPON_HIT_PED:
 			m_sQueueSample.m_nSampleIndex = SFX_BULLET_PED;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound++;
+			m_sQueueSample.m_nCounter = iSound++;
 			stereo = 1;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_BULLET_PED);
-			m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
-			m_sQueueSample.field_16 = 7;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_BULLET_PED);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
+			m_sQueueSample.m_nReleasingVolumeModificator = 7;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 30.0f;
 			maxDist = SQR(30);
 			m_sQueueSample.m_nLoopCount = 1;
@@ -6381,17 +7035,17 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[0] % 20 + 90;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			break;
 		case SOUND_SPLASH:
 			m_sQueueSample.m_nSampleIndex = SFX_SPLASH_1;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_counter = iSound++;
+			m_sQueueSample.m_nCounter = iSound++;
 			stereo = 1;
 			m_sQueueSample.m_nFrequency = RandomDisplacement(1400) + 20000;
-			m_sQueueSample.field_16 = 1;
-			m_sQueueSample.field_48 = 0.0f;
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 			m_sQueueSample.m_fSoundIntensity = 40.0f;
 			maxDist = 1600.f;
 			m_sQueueSample.m_nLoopCount = 1;
@@ -6399,50 +7053,48 @@ cAudioManager::ProcessPedOneShots(cPedParams *params)
 			emittingVol = m_anRandomTable[2] % 30 + 70;
 			m_sQueueSample.m_nLoopEnd = -1;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_56 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_bReleasingSoundFlag = 1;
 			m_sQueueSample.m_bRequireReflection = true;
 			break;
-		default:
-			SetupPedComments(params, sound);
-			continue;
+		default: SetupPedComments(params, sound); continue;
+		}
 
-			if(stereo && iSound > 60) iSound = 21;
-			if(params->m_fDistance < maxDist) {
-				CalculateDistance((bool *)params, params->m_fDistance);
-				m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
-				                                         m_sQueueSample.m_fDistance);
-				if(m_sQueueSample.m_bVolume) {
-					if(noReflection) {
-						if(0.2f * m_sQueueSample.m_fSoundIntensity >
-						   m_sQueueSample.m_fDistance) {
-							noReflection = 0;
-						} else {
-							m_sQueueSample.m_bIsDistant = true;
-							m_sQueueSample.m_bOffset = 0;
-						}
+		if(stereo && iSound > 60) iSound = 21;
+		if(params->m_fDistance < maxDist) {
+			CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
+			                  m_sQueueSample.m_fDistance);
+			if(m_sQueueSample.m_bVolume) {
+				if(noReflection) {
+					if(0.2f * m_sQueueSample.m_fSoundIntensity <=
+					   m_sQueueSample.m_fDistance) {
+						noReflection = 0;
+					} else {
+						m_sQueueSample.m_bIs2D = true;
+						m_sQueueSample.m_bOffset = 0;
+					}
+				}
+				m_sQueueSample.m_bReverbFlag = true;
+				AddSampleToRequestedQueue();
+				if(noReflection) {
+					m_sQueueSample.m_bOffset = 127;
+					++m_sQueueSample.m_nSampleIndex;
+					if(m_asAudioEntities[m_sQueueSample.m_nEntityIndex]
+					           .m_awAudioEvent[i] != SOUND_WEAPON_SHOT_FIRED ||
+					   weapon->m_eWeaponType != WEAPONTYPE_FLAMETHROWER) {
+						m_sQueueSample.m_nCounter = iSound++;
+						if(iSound > 60) iSound = 21;
+					} else {
+						++m_sQueueSample.m_nCounter;
 					}
-					m_sQueueSample.m_bReverbFlag = true;
 					AddSampleToRequestedQueue();
-					if(noReflection) {
-						m_sQueueSample.m_bOffset = 127;
-						++m_sQueueSample.m_nSampleIndex;
-						if(m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] !=
-						       47 ||
-						   weapon->m_eWeaponType != WEAPONTYPE_FLAMETHROWER) {
-							m_sQueueSample.m_counter = iSound++;
-							if(iSound > 60) iSound = 21;
-						} else {
-							++m_sQueueSample.m_counter;
-						}
-						AddSampleToRequestedQueue();
-					}
 				}
 			}
 		}
 	}
 }
-#endif
 
 void
 cAudioManager::ProcessPhysical(int32 id)
@@ -6450,8 +7102,12 @@ cAudioManager::ProcessPhysical(int32 id)
 	CPhysical *entity = (CPhysical *)m_asAudioEntities[id].m_pEntity;
 	if(entity) {
 		switch(entity->m_type) {
-		case ENTITY_TYPE_VEHICLE: ProcessVehicle((CVehicle *)m_asAudioEntities[id].m_pEntity); break;
-		case ENTITY_TYPE_PED: ProcessPed((CPhysical *)m_asAudioEntities[id].m_pEntity); break;
+		case ENTITY_TYPE_VEHICLE:
+			ProcessVehicle((CVehicle *)m_asAudioEntities[id].m_pEntity);
+			break;
+		case ENTITY_TYPE_PED:
+			ProcessPed((CPhysical *)m_asAudioEntities[id].m_pEntity);
+			break;
 		default: return;
 		}
 	}
@@ -6469,18 +7125,93 @@ cAudioManager::ProcessPlane(cVehicleParams *params)
 
 struct tVehicleSampleData {
 	eSfxSample m_nAccelerationSampleIndex;
-	char m_bEngineSoundType;
+	uint8 m_bEngineSoundType;
 	char gap_5[3];
 	eSfxSample m_nHornSample;
 	int32 m_nHornFrequency;
-	char m_nSirenOrAlarmSample;
-	int m_nSirenOrAlarmFrequency;
-	char m_bDoorType;
+	uint8 m_nSirenOrAlarmSample;
+	int32 m_nSirenOrAlarmFrequency;
+	uint8 m_bDoorType;
 	char gap_25[3];
 };
 
-int32 *CSWTCH_554 = (int32 *)0x606A50;
-tVehicleSampleData *CarSounds = (tVehicleSampleData *)0x606204;
+// int32 *GearFreqAdj = (int32 *)0x606A50;
+int32 GearFreqAdj[] = {112, 23, 0, 0, 112, 23, 0, 0, 72, 13,  0,   0,
+                       176, 4,  0, 0, 0,   0,  0, 0, 24, 252, 255, 255};
+
+// tVehicleSampleData *CarSounds = (tVehicleSampleData *)0x606204;
+
+const tVehicleSampleData CarSounds[70] = {
+    {SFX_CAR_REV_2, 2, "", SFX_CAR_HORN_JEEP, 26513, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_56CHEV, 11487, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_8, 8, "", SFX_CAR_HORN_PORSCHE, 11025, SFX_CAR_ALARM_1, 10928, 1},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_TRUCK, 29711, SFX_CAR_ALARM_1, 9935, 2},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_56CHEV, 12893, SFX_CAR_ALARM_1, 8941, 0},
+    {SFX_CAR_REV_5, 5, "", SFX_CAR_HORN_BMW328, 10706, SFX_CAR_ALARM_1, 11922, 1},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_TRUCK, 29711, SFX_CAR_ALARM_1, 7948, 2},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_TRUCK, 29711, SFX_POLICE_SIREN_SLOW, 11556, 2},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_TRUCK, 31478, SFX_CAR_ALARM_1, 8941, 2},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_BMW328, 9538, SFX_CAR_ALARM_1, 12220, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_56CHEV, 10842, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_3, 3, "", SFX_CAR_HORN_BMW328, 12017, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_2, 2, "", SFX_CAR_HORN_JEEP, 22295, SFX_CAR_ALARM_1, 12200, 1},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_BUS2, 18000, SFX_CAR_ALARM_1, 13400, 1},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_BUS, 18286, SFX_CAR_ALARM_1, 9935, 2},
+    {SFX_CAR_REV_3, 3, "", SFX_CAR_HORN_PORSCHE, 11025, SFX_CAR_ALARM_1, 13600, 1},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_JEEP, 22295, SFX_AMBULANCE_SIREN_SLOW, 8795, 2},
+    {SFX_CAR_REV_5, 5, "", SFX_CAR_HORN_PORSCHE, 9271, SFX_POLICE_SIREN_SLOW, 16168, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_56CHEV, 12170, SFX_CAR_ALARM_1, 8000, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_BUS2, 12345, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_2, 2, "", SFX_CAR_HORN_BMW328, 10796, SFX_CAR_ALARM_1, 8543, 1},
+    {SFX_CAR_REV_5, 5, "", SFX_CAR_HORN_PORSCHE, 9271, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_2, 2, "", SFX_CAR_HORN_PICKUP, 10924, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_PICKUP, 11025, SFX_ICE_CREAM_TUNE, 11025, 0},
+    {SFX_CAR_REV_7, 7, "", SFX_CAR_HORN_JEEP, 26513, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 26513, SFX_CAR_ALARM_1, 10000, 0},
+    {SFX_CAR_REV_5, 5, "", SFX_CAR_HORN_BMW328, 10706, SFX_POLICE_SIREN_SLOW, 13596, 1},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_BUS, 17260, SFX_POLICE_SIREN_SLOW, 13000, 2},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_PICKUP, 8670, SFX_CAR_ALARM_1, 9935, 2},
+    {SFX_CAR_REV_8, 8, "", SFX_CAR_HORN_PORSCHE, 10400, SFX_CAR_ALARM_1, 10123, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 26513, SFX_POLICE_SIREN_SLOW, 13596, 0},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_BUS2, 11652, SFX_CAR_ALARM_1, 10554, 3},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_TRUCK, 29711, SFX_CAR_ALARM_1, 8000, 2},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_TRUCK, 28043, SFX_CAR_ALARM_1, 9935, 2},
+    {SFX_CAR_REV_1, 0, "", SFX_CAR_HORN_TRUCK, 29711, SFX_CAR_ALARM_1, 9935, 3},
+    {SFX_CAR_REV_1, 0, "", SFX_CAR_HORN_JEEP, 26513, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CESNA_IDLE, 0, "", SFX_CAR_HORN_JEEP, 26513, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_BUS, 16291, SFX_CAR_ALARM_1, 7500, 3},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_56CHEV, 10842, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_56CHEV, 10233, SFX_CAR_ALARM_1, 8935, 0},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_PICKUP, 8670, SFX_CAR_ALARM_1, 8935, 0},
+    {SFX_CAR_REV_1, 0, "", SFX_CAR_HORN_PICKUP, 2000, SFX_CAR_ALARM_1, 17000, 0},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_5, 5, "", SFX_CAR_HORN_BMW328, 9003, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_2, 2, "", SFX_CAR_HORN_PORSCHE, 12375, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_5, 5, "", SFX_CAR_HORN_BUS2, 15554, SFX_CAR_ALARM_1, 9935, 1},
+    {SFX_CAR_REV_7, 7, "", SFX_CAR_HORN_BUS2, 13857, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_7, 7, "", SFX_CAR_HORN_PICKUP, 10924, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 2},
+    {SFX_CAR_REV_1, 0, "", SFX_CAR_HORN_JEEP, 20143, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 0, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9000, 0},
+    {SFX_CAR_REV_6, 6, "", SFX_CAR_HORN_TRUCK, 28043, SFX_CAR_ALARM_1, 9935, 2},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_BUS, 18286, SFX_CAR_ALARM_1, 9935, 2},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_56CHEV, 10842, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_4, 4, "", SFX_CAR_HORN_BUS2, 18000, SFX_CAR_ALARM_1, 13400, 1},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0},
+    {SFX_CAR_REV_1, 1, "", SFX_CAR_HORN_JEEP, 21043, SFX_CAR_ALARM_1, 9935, 0}};
 
 void
 cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *automobile)
@@ -6519,7 +7250,7 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 	processedAccelSampleStopped = 0;
 	if(bPlayerJustEnteredCar) {
 		bAccelSampleStopped = 1;
-		bPlayerJustEnteredCar = 0;
+		bPlayerJustEnteredCar = false;
 		nCruising = 0;
 		LastAccel = 0;
 		bLostTractionLastFrame = 0;
@@ -6543,7 +7274,7 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 
 	if(transmission->nDriveType == '4') {
 		wheelInUseCounter = 0;
-		for (uint8 i = 0; i < ARRAY_SIZE(automobile->m_aWheelState); i++){
+		for(uint8 i = 0; i < ARRAY_SIZE(automobile->m_aWheelState); i++) {
 			if(automobile->m_aWheelState[i]) ++wheelInUseCounter;
 		}
 		if(wheelInUseCounter > 2) lostTraction = 1;
@@ -6552,7 +7283,8 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 		   (automobile->m_aWheelState[1] || automobile->m_aWheelState[3])) {
 			lostTraction = 1;
 		}
-	} else if(transmission->nDriveType == 'R' && (automobile->m_aWheelState[1] || automobile->m_aWheelState[3])) {
+	} else if(transmission->nDriveType == 'R' &&
+	          (automobile->m_aWheelState[1] || automobile->m_aWheelState[3])) {
 		lostTraction = 1;
 	}
 	if(0.0f != velocityChange) {
@@ -6574,11 +7306,13 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 				SampleManager.StopChannel(m_bActiveSamples);
 				bAccelSampleStopped = 1;
 			}
-			if(!automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn || lostTraction) {
+			if(!automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn ||
+			   lostTraction) {
 				gasPedalAudio = automobile->m_fGasPedalAudio;
 			} else {
 				gasPedalAudio =
-				    min(1.0f, params->m_fVelocityChange / params->m_pTransmission->fMaxReverseVelocity);
+				    min(1.0f, params->m_fVelocityChange /
+				                  params->m_pTransmission->fMaxReverseVelocity);
 			}
 			gasPedalAudio = max(0.0f, gasPedalAudio);
 			automobile->m_fGasPedalAudio = gasPedalAudio;
@@ -6588,16 +7322,19 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 				bAccelSampleStopped = 1;
 			}
 			nCruising = 0;
-			if(!automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn || lostTraction ||
-			   params->m_fVelocityChange >= 0.01f && automobile->m_fGasPedalAudio > 0.2f) {
+			if(!automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn ||
+			   lostTraction ||
+			   params->m_fVelocityChange >= 0.01f &&
+			       automobile->m_fGasPedalAudio > 0.2f) {
 				automobile->m_fGasPedalAudio = automobile->m_fGasPedalAudio * 0.6f;
 				gasPedalAudio = automobile->m_fGasPedalAudio;
 			}
 			if(gasPedalAudio > 0.05f) {
 				freq = (5000.f * (gasPedalAudio - 0.05f) * 20.f / 19) + 19000;
 				if(engineSoundType == 6) freq >>= 1;
-				AddPlayerCarSample((25.f * (gasPedalAudio - 0.05f) * 20.f / 19) + 40, freq,
-				                   (soundOffset + SFX_CAR_FINGER_OFF_ACCEL_1),
+				AddPlayerCarSample((25.f * (gasPedalAudio - 0.05f) * 20.f / 19) +
+				                       40,
+				                   freq, (soundOffset + SFX_CAR_FINGER_OFF_ACCEL_1),
 				                   engineSoundType, 63, 0);
 			}
 		}
@@ -6614,16 +7351,19 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 		return;
 	}
 	if(!nCruising) {
-		if(accelerateState < 150 || !automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn ||
-		   lostTraction ||
-		   currentGear < 2 &&
-		       velocityChange - automobile->m_fVelocityChangeForAudio < 0.01f) { // here could be used abs
-			if(!automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn || lostTraction) {
-				if(!automobile->m_nWheelsOnGround && automobile->m_nDriveWheelsOnGround ||
+		if(accelerateState < 150 || !automobile->m_nWheelsOnGround ||
+		   automobile->bIsHandbrakeOn || lostTraction ||
+		   currentGear < 2 && velocityChange - automobile->m_fVelocityChangeForAudio <
+		                          0.01f) { // here could be used abs
+			if(!automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn ||
+			   lostTraction) {
+				if(!automobile->m_nWheelsOnGround &&
+				       automobile->m_nDriveWheelsOnGround ||
 				   (automobile->bIsHandbrakeOn && !bHandbrakeOnLastFrame ||
 				    lostTraction && !bLostTractionLastFrame) &&
 				       automobile->m_nWheelsOnGround) {
-					automobile->m_fGasPedalAudio = automobile->m_fGasPedalAudio * 0.6f;
+					automobile->m_fGasPedalAudio =
+					    automobile->m_fGasPedalAudio * 0.6f;
 				}
 				freqModifier = 0;
 				baseFreq = (15000.f * automobile->m_fGasPedalAudio) + 14000;
@@ -6661,13 +7401,14 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 			SampleManager.SetChannel3DPosition(m_bActiveSamples, pos.x, pos.y, pos.z);
 			SampleManager.SetChannel3DDistances(m_bActiveSamples, 50.f, 12.5f);
 			if(engineSoundType == 6)
-				freq = (CSWTCH_554[CurrentPretendGear] + freqModifier + 22050) >> 1;
+				freq =
+				    (GearFreqAdj[CurrentPretendGear] + freqModifier + 22050) >> 1;
 			else
-				freq = CSWTCH_554[CurrentPretendGear] + freqModifier + 22050;
+				freq = GearFreqAdj[CurrentPretendGear] + freqModifier + 22050;
 			SampleManager.SetChannelFrequency(m_bActiveSamples, freq);
 			if(!channelUsed) {
-				SampleManager.SetChannelReverbFlag(m_bActiveSamples,
-				                                   m_bDynamicAcousticModelingStatus != 0);
+				SampleManager.SetChannelReverbFlag(
+				    m_bActiveSamples, m_bDynamicAcousticModelingStatus != 0);
 				SampleManager.StartChannel(m_bActiveSamples);
 			}
 			LastAccel = accelerateState;
@@ -6677,20 +7418,22 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 			return;
 		}
 		if(processedAccelSampleStopped) {
-			if(!SampleManager.InitialiseChannel(m_bActiveSamples, soundOffset + 345, 0)) return;
+			if(!SampleManager.InitialiseChannel(m_bActiveSamples, soundOffset + 345, 0))
+				return;
 			SampleManager.SetChannelLoopCount(m_bActiveSamples, 1);
 			SampleManager.SetChannelLoopPoints(m_bActiveSamples, 0, -1);
 			SampleManager.SetChannelEmittingVolume(m_bActiveSamples, 85);
 			SampleManager.SetChannel3DPosition(m_bActiveSamples, pos.x, pos.y, pos.z);
 			SampleManager.SetChannel3DDistances(m_bActiveSamples, 50.f, 12.5f);
 			if(engineSoundType == 6)
-				freq = (CSWTCH_554[CurrentPretendGear] + freqModifier + 22050) >> 1;
+				freq =
+				    (GearFreqAdj[CurrentPretendGear] + freqModifier + 22050) >> 1;
 			else
-				freq = CSWTCH_554[CurrentPretendGear] + freqModifier + 22050;
+				freq = GearFreqAdj[CurrentPretendGear] + freqModifier + 22050;
 			SampleManager.SetChannelFrequency(m_bActiveSamples, freq);
 			if(!channelUsed) {
-				SampleManager.SetChannelReverbFlag(m_bActiveSamples,
-				                                   m_bDynamicAcousticModelingStatus != 0);
+				SampleManager.SetChannelReverbFlag(
+				    m_bActiveSamples, m_bDynamicAcousticModelingStatus != 0);
 				SampleManager.StartChannel(m_bActiveSamples);
 			}
 			LastAccel = accelerateState;
@@ -6701,20 +7444,21 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 		}
 		if(CurrentPretendGear < params->m_pTransmission->nNumberOfGears - 1) {
 			++CurrentPretendGear;
-			if(!SampleManager.InitialiseChannel(m_bActiveSamples, soundOffset + 345, 0)) return;
+			if(!SampleManager.InitialiseChannel(m_bActiveSamples, soundOffset + 345, 0))
+				return;
 			SampleManager.SetChannelLoopCount(m_bActiveSamples, 1);
 			SampleManager.SetChannelLoopPoints(m_bActiveSamples, 0, -1);
 			SampleManager.SetChannelEmittingVolume(m_bActiveSamples, 85);
 			SampleManager.SetChannel3DPosition(m_bActiveSamples, pos.x, pos.y, pos.z);
 			SampleManager.SetChannel3DDistances(m_bActiveSamples, 50.f, 12.5f);
-			freq = CSWTCH_554[CurrentPretendGear] + freqModifier + 22050;
+			freq = GearFreqAdj[CurrentPretendGear] + freqModifier + 22050;
 
 			if(engineSoundType == 6) freq >>= 1;
 
 			SampleManager.SetChannelFrequency(m_bActiveSamples, freq);
 			if(!channelUsed) {
-				SampleManager.SetChannelReverbFlag(m_bActiveSamples,
-				                                   m_bDynamicAcousticModelingStatus != 0);
+				SampleManager.SetChannelReverbFlag(
+				    m_bActiveSamples, m_bDynamicAcousticModelingStatus != 0);
 				SampleManager.StartChannel(m_bActiveSamples);
 			}
 			LastAccel = accelerateState;
@@ -6726,8 +7470,8 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 		nCruising = 1;
 	}
 	bAccelSampleStopped = 1;
-	if(accelerateState < 150 || !automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn || lostTraction ||
-	   currentGear < params->m_pTransmission->nNumberOfGears - 1) {
+	if(accelerateState < 150 || !automobile->m_nWheelsOnGround || automobile->bIsHandbrakeOn ||
+	   lostTraction || currentGear < params->m_pTransmission->nNumberOfGears - 1) {
 		nCruising = 0;
 	} else {
 		if(accelerateState >= 220 &&
@@ -6738,8 +7482,8 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *
 		}
 		freq = 27 * nCruising + freqModifier + 22050;
 		if(engineSoundType == 6) freq >>= 1;
-		AddPlayerCarSample(85, freq, (soundOffset + SFX_CAR_AFTER_ACCEL_1),
-		                   engineSoundType, 64, 1);
+		AddPlayerCarSample(85, freq, (soundOffset + SFX_CAR_AFTER_ACCEL_1), engineSoundType,
+		                   64, 1);
 	}
 	LastAccel = accelerateState;
 
@@ -6778,18 +7522,20 @@ cAudioManager::ProcessPoliceCellBeatingScriptObject(uint8 sound)
 			m_sQueueSample.m_nSampleIndex = sampleIndex;
 			emittingVol = m_anRandomTable[0] % 50 + 55;
 			m_sQueueSample.m_bVolume =
-			    ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			    ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
+			                  m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 16);
-				m_sQueueSample.m_counter = counter++;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency / 16);
+				m_sQueueSample.m_nCounter = counter++;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
@@ -6861,21 +7607,23 @@ cAudioManager::ProcessPornCinema(uint8 sound)
 		m_sQueueSample.m_fDistance = Sqrt(distSquared);
 		if(sound != SCRIPT_SOUND_MISTY_SEX_S && sound != SCRIPT_SOUND_MISTY_SEX_L) {
 			m_sQueueSample.m_bVolume =
-			    ComputeVolume(maxVolume, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			    ComputeVolume(maxVolume, m_sQueueSample.m_fSoundIntensity,
+			                  m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_counter = 0;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nCounter = 0;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 0;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 2.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 				m_sQueueSample.m_bEmittingVolume = maxVolume;
 				m_sQueueSample.m_nLoopStart =
-				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
 				m_sQueueSample.m_bReverbFlag = true;
 				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
@@ -6884,20 +7632,21 @@ cAudioManager::ProcessPornCinema(uint8 sound)
 
 		time = CTimer::GetTimeInMilliseconds();
 		if(time > gPornNextTime) {
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(90, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    90, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
 				rand = m_anRandomTable[1] & 1;
 				m_sQueueSample.m_nSampleIndex = rand + sample;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
-				m_sQueueSample.m_counter = rand + 1;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nFrequency +=
+				    RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+				m_sQueueSample.m_nCounter = rand + 1;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 6;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 6;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
 				m_sQueueSample.m_bReverbFlag = true;
@@ -6924,7 +7673,7 @@ cAudioManager::ProcessProjectiles()
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_ROCKET_FLY);
-				m_sQueueSample.field_16 = 3;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
 				break;
 			case WEAPONTYPE_MOLOTOV:
 				emittingVol = molotovVolume;
@@ -6933,28 +7682,32 @@ cAudioManager::ProcessProjectiles()
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 				m_sQueueSample.m_nFrequency =
 				    32 * SampleManager.GetSampleBaseFrequency(SFX_PED_ON_FIRE) / 25;
-				m_sQueueSample.field_16 = 7;
+				m_sQueueSample.m_nReleasingVolumeModificator = 7;
 				break;
 			default: return;
 			}
-			m_sQueueSample.field_48 = 4.0f;
-			m_sQueueSample.field_76 = 3;
-			m_sQueueSample.m_vecPos = CProjectileInfo::ms_apProjectile[i]->GetPosition();
+			m_sQueueSample.m_fSpeedMultiplier = 4.0f;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
+			m_sQueueSample.m_vecPos =
+			    CProjectileInfo::ms_apProjectile[i]->GetPosition();
 			float distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 			if(distSquared < SQR(m_sQueueSample.m_fSoundIntensity)) {
 				m_sQueueSample.m_fDistance = Sqrt(distSquared);
-				m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
-				                                         m_sQueueSample.m_fDistance);
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
+				                  m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
-					m_sQueueSample.m_counter = i;
-					m_sQueueSample.m_bIsDistant = false;
+					m_sQueueSample.m_nCounter = i;
+					m_sQueueSample.m_bIs2D = false;
 					m_sQueueSample.m_nLoopCount = 0;
 					m_sQueueSample.m_bEmittingVolume = emittingVol;
 					m_sQueueSample.m_nLoopStart =
-					    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopStartOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_nLoopEnd =
-					    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-					m_sQueueSample.field_56 = 0;
+					    SampleManager.GetSampleLoopEndOffset(
+					        m_sQueueSample.m_nSampleIndex);
+					m_sQueueSample.m_bReleasingSoundFlag = false;
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bRequireReflection = false;
 					AddSampleToRequestedQueue();
@@ -6967,35 +7720,32 @@ cAudioManager::ProcessProjectiles()
 void
 cAudioManager::ProcessRainOnVehicle(cVehicleParams *params)
 {
-	float emittingVol;
-	CVehicle *veh;
-
 	if(params->m_fDistance < SQR(rainOnVehicleIntensity) && CWeather::Rain > 0.01f &&
 	   (!CCullZones::CamNoRain() || !CCullZones::PlayerNoRain())) {
-		++params->m_pVehicle->m_bRainAudioCounter;
-		veh = params->m_pVehicle;
+		CVehicle *veh = params->m_pVehicle;
+		++veh->m_bRainAudioCounter;
 		if(veh->m_bRainAudioCounter >= 2) {
 			veh->m_bRainAudioCounter = 0;
 			CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
-			emittingVol = 30.f * CWeather::Rain;
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(emittingVol, rainOnVehicleIntensity, m_sQueueSample.m_fDistance);
+			float emittingVol = 30.f * CWeather::Rain;
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    emittingVol, rainOnVehicleIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_counter = veh->m_bRainSamplesCounter++;
-				veh = params->m_pVehicle;
+				m_sQueueSample.m_nCounter = veh->m_bRainSamplesCounter++;
 				if(veh->m_bRainSamplesCounter > 4) veh->m_bRainSamplesCounter = 68;
-				m_sQueueSample.m_nSampleIndex = (m_anRandomTable[1] & 3) + SFX_CAR_RAIN_1;
+				m_sQueueSample.m_nSampleIndex =
+				    (m_anRandomTable[1] & 3) + SFX_CAR_RAIN_1;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 9;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 9;
 				m_sQueueSample.m_nFrequency = m_anRandomTable[1] % 4000 + 28000;
 				m_sQueueSample.m_nLoopCount = 1;
 				m_sQueueSample.m_bEmittingVolume = (uint8)emittingVol;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
-				m_sQueueSample.field_48 = 0.0f;
+				m_sQueueSample.m_fSpeedMultiplier = 0.0f;
 				m_sQueueSample.m_fSoundIntensity = rainOnVehicleIntensity;
-				m_sQueueSample.field_56 = 1;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
 				m_sQueueSample.m_bReverbFlag = false;
 				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
@@ -7008,8 +7758,16 @@ void
 cAudioManager::ProcessReverb() const
 {
 	if(SampleManager.UpdateReverb() && m_bDynamicAcousticModelingStatus) {
-		for(uint32 i = 0; i < channels; i++) { // bug? 
-			if(m_asActiveSamples[i].m_bReverbFlag) SampleManager.SetChannelReverbFlag(i, 1);
+		for(uint32 i = 0; i <
+#ifdef FIX_BUGS
+		                  channels
+#else
+		                  28
+#endif
+		    ;
+		    i++) {
+			if(m_asActiveSamples[i].m_bReverbFlag)
+				SampleManager.SetChannelReverbFlag(i, 1);
 		}
 	}
 }
@@ -7028,7 +7786,8 @@ cAudioManager::ProcessReverseGear(cVehicleParams *params)
 		CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 		automobile = (CAutomobile *)params->m_pVehicle;
 		if(automobile->m_nWheelsOnGround) {
-			modificator = params->m_fVelocityChange / params->m_pTransmission->fMaxReverseVelocity;
+			modificator = params->m_fVelocityChange /
+			              params->m_pTransmission->fMaxReverseVelocity;
 		} else {
 			if(automobile->m_nDriveWheelsOnGround)
 				automobile->m_fGasPedalAudio = automobile->m_fGasPedalAudio * 0.4f;
@@ -7036,28 +7795,30 @@ cAudioManager::ProcessReverseGear(cVehicleParams *params)
 		}
 		modificator = Abs(modificator);
 		emittingVol = (24.f * modificator);
-		m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, reverseGearIntensity, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume =
+		    ComputeVolume(emittingVol, reverseGearIntensity, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
 			if(params->m_pVehicle->m_fGasPedal >= 0.0f) {
-				m_sQueueSample.m_counter = 62;
+				m_sQueueSample.m_nCounter = 62;
 				m_sQueueSample.m_nSampleIndex = SFX_REVERSE_GEAR_2;
 			} else {
-				m_sQueueSample.m_counter = 61;
+				m_sQueueSample.m_nCounter = 61;
 				m_sQueueSample.m_nSampleIndex = SFX_REVERSE_GEAR;
 			}
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 3;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
 			m_sQueueSample.m_nFrequency = (6000.f * modificator) + 7000;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 3.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 3.0f;
 			m_sQueueSample.m_fSoundIntensity = reverseGearIntensity;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 5;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 5;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -7087,36 +7848,38 @@ cAudioManager::ProcessSawMillScriptObject(uint8 sound)
 		if(m_sQueueSample.m_bVolume) {
 			m_sQueueSample.m_nSampleIndex = SFX_SAWMILL_LOOP;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_SAWMILL_LOOP);
-			m_sQueueSample.m_counter = 0;
-			m_sQueueSample.m_bIsDistant = false;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_SAWMILL_LOOP);
+			m_sQueueSample.m_nCounter = 0;
+			m_sQueueSample.m_bIs2D = false;
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_16 = 5;
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_bEmittingVolume = 30;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
 		}
 		time = CTimer::GetTimeInMilliseconds();
 		if(time > gSawMillNextTime) {
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(70, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    70, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
 				m_sQueueSample.m_nSampleIndex = SFX_SAWMILL_CUT_WOOD;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_counter = 1;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nCounter = 1;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 2.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
 				m_sQueueSample.m_bReverbFlag = true;
@@ -7150,9 +7913,7 @@ cAudioManager::ProcessShopScriptObject(uint8 sound)
 
 	switch(sound) {
 	case SCRIPT_SOUND_SHOP_LOOP_S:
-	case SCRIPT_SOUND_SHOP_LOOP_L:
-		m_sQueueSample.m_fSoundIntensity = 30.0f;
-		break;
+	case SCRIPT_SOUND_SHOP_LOOP_L: m_sQueueSample.m_fSoundIntensity = 30.0f; break;
 	default: return;
 	}
 	distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
@@ -7163,37 +7924,39 @@ cAudioManager::ProcessShopScriptObject(uint8 sound)
 		if(m_sQueueSample.m_bVolume) {
 			m_sQueueSample.m_nSampleIndex = SFX_SHOP_LOOP;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_SHOP_LOOP);
-			m_sQueueSample.m_counter = 0;
-			m_sQueueSample.m_bIsDistant = false;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_SHOP_LOOP);
+			m_sQueueSample.m_nCounter = 0;
+			m_sQueueSample.m_bIs2D = false;
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_16 = 5;
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_bEmittingVolume = 30;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
 		}
 		time = CTimer::GetTimeInMilliseconds();
 		if(time > gShopNextTime) {
-			m_sQueueSample.m_bVolume =
-			    ComputeVolume(70, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume = ComputeVolume(
+			    70, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
 				rand = m_anRandomTable[1] & 1;
 				m_sQueueSample.m_nSampleIndex = rand + SFX_SHOP_TILL_1;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_nFrequency =
-				    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_counter = rand + 1;
-				m_sQueueSample.m_bIsDistant = false;
+				m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nCounter = rand + 1;
+				m_sQueueSample.m_bIs2D = false;
 				m_sQueueSample.m_nLoopCount = 1;
-				m_sQueueSample.field_56 = 1;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.field_48 = 2.0f;
+				m_sQueueSample.m_bReleasingSoundFlag = true;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 				m_sQueueSample.m_bEmittingVolume = 70;
 				m_sQueueSample.m_nLoopStart = 0;
 				m_sQueueSample.m_nLoopEnd = -1;
@@ -7223,7 +7986,8 @@ cAudioManager::ProcessSpecial()
 		CPlayerPed *playerPed = FindPlayerPed();
 		if(playerPed) {
 			const PedState &state = playerPed->m_nPedState;
-			if(state != PED_ENTER_CAR && state != PED_STEAL_CAR && !playerPed->bInVehicle)
+			if(state != PED_ENTER_CAR && state != PED_STEAL_CAR &&
+			   !playerPed->bInVehicle)
 				SampleManager.StopChannel(m_bActiveSamples);
 		}
 	}
@@ -7244,49 +8008,55 @@ cAudioManager::ProcessTrainNoise(cVehicleParams *params)
 		speedMultipler = min(1.0f, train->m_fSpeed * 250.f / 51.f);
 		emittingVol = (75.f * speedMultipler);
 		if(train->m_fWagonPosition == 0.0f) {
-			m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 300.f, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, 300.f, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_counter = 32;
+				m_sQueueSample.m_nCounter = 32;
 				m_sQueueSample.m_nSampleIndex = SFX_TRAIN_FAR;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 2;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 2;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_TRAIN_FAR);
 				m_sQueueSample.m_nLoopCount = 0;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
 				m_sQueueSample.m_nLoopStart =
-				    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-				    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.field_48 = 3.0f;
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_fSpeedMultiplier = 3.0f;
 				m_sQueueSample.m_fSoundIntensity = 300.0f;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_76 = 3;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
+				m_sQueueSample.m_nReleasingVolumeDivider = 3;
 				m_sQueueSample.m_bReverbFlag = true;
 				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
 			}
 		}
 		if(params->m_fDistance < 4900.f) {
-			m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 70.f, m_sQueueSample.m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, 70.f, m_sQueueSample.m_fDistance);
 			if(m_sQueueSample.m_bVolume) {
-				m_sQueueSample.m_counter = 33;
+				m_sQueueSample.m_nCounter = 33;
 				m_sQueueSample.m_nSampleIndex = SFX_TRAIN_NEAR;
 				m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-				m_sQueueSample.m_bIsDistant = false;
-				m_sQueueSample.field_16 = 5;
+				m_sQueueSample.m_bIs2D = false;
+				m_sQueueSample.m_nReleasingVolumeModificator = 5;
 				m_sQueueSample.m_nFrequency =
 				    SampleManager.GetSampleBaseFrequency(SFX_TRAIN_NEAR) +
 				    100 * m_sQueueSample.m_nEntityIndex % 987;
 				m_sQueueSample.m_nLoopCount = 0;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
-				m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.field_48 = 6.0f;
+				m_sQueueSample.m_nLoopStart =
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 				m_sQueueSample.m_fSoundIntensity = 70.0f;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_76 = 3;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
+				m_sQueueSample.m_nReleasingVolumeDivider = 3;
 				m_sQueueSample.m_bReverbFlag = true;
 				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
@@ -7317,7 +8087,8 @@ cAudioManager::ProcessVehicle(CVehicle *veh)
 	if(params.m_pVehicle->m_status == STATUS_SIMPLE)
 		velChange = params.m_pVehicle->AutoPilot.m_fMaxTrafficSpeed * 0.02f;
 	else
-		velChange = DotProduct(params.m_pVehicle->m_vecMoveSpeed, params.m_pVehicle->GetForward());
+		velChange =
+		    DotProduct(params.m_pVehicle->m_vecMoveSpeed, params.m_pVehicle->GetForward());
 	params.m_fVelocityChange = velChange;
 	switch(params.m_pVehicle->m_vehType) {
 	case VEHICLE_TYPE_CAR:
@@ -7332,7 +8103,8 @@ cAudioManager::ProcessVehicle(CVehicle *veh)
 		if(params.m_nIndex == DODO) {
 			if(!ProcessVehicleRoadNoise(&params)) {
 				ProcessVehicleOneShots(&params);
-				((CAutomobile *)veh)->m_fVelocityChangeForAudio = params.m_fVelocityChange;
+				((CAutomobile *)veh)->m_fVelocityChangeForAudio =
+				    params.m_fVelocityChange;
 				ProcessRainOnVehicle(&params);
 				break;
 			}
@@ -7341,7 +8113,8 @@ cAudioManager::ProcessVehicle(CVehicle *veh)
 		} else {
 			if(!ProcessVehicleRoadNoise(&params)) {
 				ProcessVehicleOneShots(&params);
-				((CAutomobile *)veh)->m_fVelocityChangeForAudio = params.m_fVelocityChange;
+				((CAutomobile *)veh)->m_fVelocityChangeForAudio =
+				    params.m_fVelocityChange;
 				ProcessRainOnVehicle(&params);
 				break;
 			}
@@ -7350,7 +8123,8 @@ cAudioManager::ProcessVehicle(CVehicle *veh)
 			ProcessVehicleSkidding(&params);
 			ProcessVehicleHorn(&params);
 			ProcessVehicleSirenOrAlarm(&params);
-			if(UsesReverseWarning(params.m_nIndex)) ProcessVehicleReverseWarning(&params);
+			if(UsesReverseWarning(params.m_nIndex))
+				ProcessVehicleReverseWarning(&params);
 			if(HasAirBrakes(params.m_nIndex)) ProcessAirBrakes(&params);
 		}
 		ProcessCarBombTick(&params);
@@ -7405,25 +8179,26 @@ cAudioManager::ProcessVehicleDoors(cVehicleParams *params)
 				velocity = min(0.3f, Abs(automobile->Doors[i].m_fAngVel));
 				if(velocity > 0.0035f) {
 					emittingVol = (100.f * velocity * 10.f / 3.f);
-					m_sQueueSample.m_bVolume =
-					    ComputeVolume(emittingVol, 40.f, m_sQueueSample.m_fDistance);
+					m_sQueueSample.m_bVolume = ComputeVolume(
+					    emittingVol, 40.f, m_sQueueSample.m_fDistance);
 					if(m_sQueueSample.m_bVolume) {
-						m_sQueueSample.m_counter = i + 6;
+						m_sQueueSample.m_nCounter = i + 6;
 						m_sQueueSample.m_nSampleIndex =
 						    m_anRandomTable[1] % 6 + SFX_COL_CAR_PANEL_1;
-						m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(
-						                                  m_sQueueSample.m_nSampleIndex) +
-						                              RandomDisplacement(1000);
+						m_sQueueSample.m_nFrequency =
+						    SampleManager.GetSampleBaseFrequency(
+						        m_sQueueSample.m_nSampleIndex) +
+						    RandomDisplacement(1000);
 						m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-						m_sQueueSample.m_bIsDistant = false;
-						m_sQueueSample.field_16 = 10;
+						m_sQueueSample.m_bIs2D = false;
+						m_sQueueSample.m_nReleasingVolumeModificator = 10;
 						m_sQueueSample.m_nLoopCount = 1;
 						m_sQueueSample.m_bEmittingVolume = emittingVol;
 						m_sQueueSample.m_nLoopStart = 0;
 						m_sQueueSample.m_nLoopEnd = -1;
-						m_sQueueSample.field_48 = 1.0f;
+						m_sQueueSample.m_fSpeedMultiplier = 1.0f;
 						m_sQueueSample.m_fSoundIntensity = 40.0f;
-						m_sQueueSample.field_56 = 1;
+						m_sQueueSample.m_bReleasingSoundFlag = true;
 						m_sQueueSample.m_bReverbFlag = true;
 						m_sQueueSample.m_bRequireReflection = true;
 						AddSampleToRequestedQueue();
@@ -7436,218 +8211,244 @@ cAudioManager::ProcessVehicleDoors(cVehicleParams *params)
 }
 
 void
-cAudioManager::ProcessVehicleEngine(cVehicleParams* params)
+cAudioManager::ProcessVehicleEngine(cVehicleParams *params)
 {
-	CVehicle* playerVeh;
-	CVehicle* veh;
-	CAutomobile* automobile;
+	CVehicle *playerVeh;
+	CVehicle *veh;
+	CAutomobile *automobile;
 	float relativeGearChange;
 	float relativeChange;
 	float reverseRelativechange;
 	uint8 volume;
 	eSfxSample accelerationSample;
-	int32 freq;
+	int32 freq = 0; // uinitialized variable
 	uint8 emittingVol;
-	cTransmission* transmission;
+	cTransmission *transmission;
 	uint8 currentGear;
 	float modificator;
 	float traction = 0.f;
 
-	if (params->m_fDistance < SQR(50.f)) {
+	if(params->m_fDistance < SQR(50.f)) {
 		playerVeh = FindPlayerVehicle();
 		veh = params->m_pVehicle;
-		if (playerVeh == veh && veh->m_status == STATUS_WRECKED) {
+		if(playerVeh == veh && veh->m_status == STATUS_WRECKED) {
 			SampleManager.StopChannel(m_bActiveSamples);
 			return;
 		}
-		if (veh->bEngineOn) {
+		if(veh->bEngineOn) {
 			CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
-			automobile = (CAutomobile*)params->m_pVehicle;
-			if (params->m_nIndex == DODO) {
+			automobile = (CAutomobile *)params->m_pVehicle;
+			if(params->m_nIndex == DODO) {
 				ProcessCesna(params);
 				return;
 			}
-			if (FindPlayerVehicle() == veh) {
+			if(FindPlayerVehicle() == veh) {
 				ProcessPlayersVehicleEngine(params, automobile);
 				return;
 			}
 			transmission = params->m_pTransmission;
-			if (transmission) {
+			if(transmission) {
 				currentGear = params->m_pVehicle->m_nCurrentGear;
-				if (automobile->m_nWheelsOnGround) {
-					if (automobile->bIsHandbrakeOn) {
-						if (0.f == params->m_fVelocityChange) traction = 0.9f;
-					}
-					else if (params->m_pVehicle->m_status == STATUS_SIMPLE) {
+				if(automobile->m_nWheelsOnGround) {
+					if(automobile->bIsHandbrakeOn) {
+						if(0.f == params->m_fVelocityChange)
+							traction = 0.9f;
+					} else if(params->m_pVehicle->m_status == STATUS_SIMPLE) {
 						traction = 0.f;
-					}
-					else {
-						switch (transmission->nDriveType) {
+					} else {
+						switch(transmission->nDriveType) {
 						case '4':
-							for (int32 i = 0; i < ARRAY_SIZE(automobile->m_aWheelState); i++) {
-								if (automobile->m_aWheelState[i] == WHEEL_STATE_SPINNING)
+							for(int32 i = 0;
+							    i <
+							    ARRAY_SIZE(automobile->m_aWheelState);
+							    i++) {
+								if(automobile->m_aWheelState[i] ==
+								   WHEEL_STATE_SPINNING)
 									traction += 0.05f;
 							}
 							break;
 						case 'F':
-							if (automobile->m_aWheelState[0] == WHEEL_STATE_SPINNING)
+							if(automobile->m_aWheelState[0] ==
+							   WHEEL_STATE_SPINNING)
 								traction += 0.1f;
-							if (automobile->m_aWheelState[2] == WHEEL_STATE_SPINNING)
+							if(automobile->m_aWheelState[2] ==
+							   WHEEL_STATE_SPINNING)
 								traction += 0.1f;
 							break;
 						case 'R':
-							if (automobile->m_aWheelState[1] == WHEEL_STATE_SPINNING)
+							if(automobile->m_aWheelState[1] ==
+							   WHEEL_STATE_SPINNING)
 								traction += 0.1f;
-							if (automobile->m_aWheelState[3] == WHEEL_STATE_SPINNING)
+							if(automobile->m_aWheelState[3] ==
+							   WHEEL_STATE_SPINNING)
 								traction += 0.1f;
 							break;
 						}
 					}
-					if (transmission->fMaxVelocity <= 0.f) {
+					if(transmission->fMaxVelocity <= 0.f) {
 						relativeChange = 0.f;
-					}
-					else if (currentGear) {
-						if ((params->m_fVelocityChange -
-							transmission->Gears[currentGear].fShiftDownVelocity) /
-							transmission->fMaxVelocity * 2.5f <=
-							1.f)
+					} else if(currentGear) {
+						if((params->m_fVelocityChange -
+						    transmission->Gears[currentGear]
+						        .fShiftDownVelocity) /
+						       transmission->fMaxVelocity * 2.5f <=
+						   1.f)
 							relativeGearChange =
-							(params->m_fVelocityChange -
-								transmission->Gears[currentGear].fShiftDownVelocity) /
-							transmission->fMaxVelocity * 2.5f;
+							    (params->m_fVelocityChange -
+							     transmission->Gears[currentGear]
+							         .fShiftDownVelocity) /
+							    transmission->fMaxVelocity * 2.5f;
 						else
 							relativeGearChange = 1.f;
-						if (0.f == traction && automobile->m_status != STATUS_SIMPLE &&
-							params->m_fVelocityChange >=
-							transmission->Gears[1].fShiftUpVelocity) {
+						if(0.f == traction &&
+						   automobile->m_status != STATUS_SIMPLE &&
+						   params->m_fVelocityChange >=
+						       transmission->Gears[1].fShiftUpVelocity) {
 							traction = 0.7f;
 						}
-						relativeChange = traction * automobile->m_fGasPedalAudio * 0.95f +
-							(1.f - traction) * relativeGearChange;
-					}
-					else {
-						reverseRelativechange =
-							Abs((params->m_fVelocityChange -
-								transmission->Gears[0].fShiftDownVelocity) /
-								transmission->fMaxReverseVelocity);
-						if (1.f - reverseRelativechange <= 1.f) {
-							relativeChange = 1.f - reverseRelativechange;
-						}
-						else {
+						relativeChange =
+						    traction * automobile->m_fGasPedalAudio *
+						        0.95f +
+						    (1.f - traction) * relativeGearChange;
+					} else {
+						reverseRelativechange = Abs(
+						    (params->m_fVelocityChange -
+						     transmission->Gears[0].fShiftDownVelocity) /
+						    transmission->fMaxReverseVelocity);
+						if(1.f - reverseRelativechange <= 1.f) {
+							relativeChange =
+							    1.f - reverseRelativechange;
+						} else {
 							relativeChange = 1.f;
 						}
 					}
-				}
-				else {
-					if (automobile->m_nDriveWheelsOnGround)
-						automobile->m_fGasPedalAudio = automobile->m_fGasPedalAudio * 0.4f;
+				} else {
+					if(automobile->m_nDriveWheelsOnGround)
+						automobile->m_fGasPedalAudio =
+						    automobile->m_fGasPedalAudio * 0.4f;
 					relativeChange = automobile->m_fGasPedalAudio;
 				}
 				modificator = relativeChange;
-				if (currentGear || !automobile->m_nWheelsOnGround)
+				if(currentGear || !automobile->m_nWheelsOnGround)
 					freq = 1200 * currentGear + 18000.f * modificator + 14000;
 				else
 					freq = 13000.f * modificator + 14000;
-				if (modificator >= 0.75f) {
+				if(modificator >= 0.75f) {
 					emittingVol = 120;
-					volume = ComputeVolume(120, 50.f, m_sQueueSample.m_fDistance);
-				}
-				else {
+					volume =
+					    ComputeVolume(120, 50.f, m_sQueueSample.m_fDistance);
+				} else {
 					emittingVol = modificator * 4 / 3 * 40.f + 80.f;
-					volume = ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance);
+					volume = ComputeVolume(emittingVol, 50.f,
+					                       m_sQueueSample.m_fDistance);
 				}
-			}
-			else {
+			} else {
 				modificator = 0.f;
 				emittingVol = 80;
 				volume = ComputeVolume(80, 50.f, m_sQueueSample.m_fDistance);
 			}
 			m_sQueueSample.m_bVolume = volume;
-			if (m_sQueueSample.m_bVolume) {
-				if (automobile->m_status == STATUS_SIMPLE) {
-					if (modificator < 0.02f) {
+			if(m_sQueueSample.m_bVolume) {
+				if(automobile->m_status == STATUS_SIMPLE) {
+					if(modificator < 0.02f) {
 						m_sQueueSample.m_nSampleIndex =
-							CarSounds[params->m_nIndex].m_bEngineSoundType + SFX_CAR_REV_10;
+						    CarSounds[params->m_nIndex].m_bEngineSoundType +
+						    SFX_CAR_REV_10;
 						freq = 10000.f * modificator + 22050;
-						m_sQueueSample.m_counter = 52;
+						m_sQueueSample.m_nCounter = 52;
 						m_sQueueSample.m_bBankIndex = 0;
-						m_sQueueSample.m_bIsDistant = 0;
-						m_sQueueSample.field_16 = 3;
+						m_sQueueSample.m_bIs2D = 0;
+						m_sQueueSample.m_nReleasingVolumeModificator = 3;
 						m_sQueueSample.m_nFrequency =
-							freq + 100 * m_sQueueSample.m_nEntityIndex % 1000;
-						if (m_sQueueSample.m_nSampleIndex == SFX_CAR_IDLE_6 ||
-							m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
-							m_sQueueSample.m_nFrequency = m_sQueueSample.m_nFrequency >> 1;
+						    freq +
+						    100 * m_sQueueSample.m_nEntityIndex % 1000;
+						if(m_sQueueSample.m_nSampleIndex ==
+						       SFX_CAR_IDLE_6 ||
+						   m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
+							m_sQueueSample.m_nFrequency =
+							    m_sQueueSample.m_nFrequency >> 1;
 						m_sQueueSample.m_nLoopCount = 0;
 						m_sQueueSample.m_bEmittingVolume = emittingVol;
-						m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(
-							m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_nLoopStart =
+						    SampleManager.GetSampleLoopStartOffset(
+						        m_sQueueSample.m_nSampleIndex);
 						m_sQueueSample.m_nLoopEnd =
-							SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-						m_sQueueSample.field_48 = 6.0f;
+						    SampleManager.GetSampleLoopEndOffset(
+						        m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 						m_sQueueSample.m_fSoundIntensity = 50.0f;
-						m_sQueueSample.field_56 = 0;
-						m_sQueueSample.field_76 = 8;
+						m_sQueueSample.m_bReleasingSoundFlag = false;
+						m_sQueueSample.m_nReleasingVolumeDivider = 8;
 						m_sQueueSample.m_bReverbFlag = 1;
 						m_sQueueSample.m_bRequireReflection = 0;
 						AddSampleToRequestedQueue();
 						return;
 					}
-					accelerationSample = CarSounds[params->m_nIndex].m_nAccelerationSampleIndex;
-				}
-				else {
-					if (automobile->m_fGasPedal < 0.05f) {
+					accelerationSample =
+					    CarSounds[params->m_nIndex].m_nAccelerationSampleIndex;
+				} else {
+					if(automobile->m_fGasPedal < 0.05f) {
 						m_sQueueSample.m_nSampleIndex =
-							CarSounds[params->m_nIndex].m_bEngineSoundType +
-							SFX_CAR_REV_10; // to recheck idle sounds start 1 postion later
+						    CarSounds[params->m_nIndex].m_bEngineSoundType +
+						    SFX_CAR_REV_10; // to recheck idle sounds start
+						                    // 1 postion later
 						freq = 10000.f * modificator + 22050;
-						m_sQueueSample.m_counter = 52;
+						m_sQueueSample.m_nCounter = 52;
 						m_sQueueSample.m_bBankIndex = 0;
-						m_sQueueSample.m_bIsDistant = 0;
-						m_sQueueSample.field_16 = 3;
+						m_sQueueSample.m_bIs2D = 0;
+						m_sQueueSample.m_nReleasingVolumeModificator = 3;
 						m_sQueueSample.m_nFrequency =
-							freq + 100 * m_sQueueSample.m_nEntityIndex % 1000;
-						if (m_sQueueSample.m_nSampleIndex == SFX_CAR_IDLE_6 ||
-							m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
-							m_sQueueSample.m_nFrequency = m_sQueueSample.m_nFrequency >> 1;
+						    freq +
+						    100 * m_sQueueSample.m_nEntityIndex % 1000;
+						if(m_sQueueSample.m_nSampleIndex ==
+						       SFX_CAR_IDLE_6 ||
+						   m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
+							m_sQueueSample.m_nFrequency =
+							    m_sQueueSample.m_nFrequency >> 1;
 						m_sQueueSample.m_nLoopCount = 0;
 						m_sQueueSample.m_bEmittingVolume = emittingVol;
-						m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(
-							m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_nLoopStart =
+						    SampleManager.GetSampleLoopStartOffset(
+						        m_sQueueSample.m_nSampleIndex);
 						m_sQueueSample.m_nLoopEnd =
-							SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-						m_sQueueSample.field_48 = 6.0f;
+						    SampleManager.GetSampleLoopEndOffset(
+						        m_sQueueSample.m_nSampleIndex);
+						m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 						m_sQueueSample.m_fSoundIntensity = 50.0f;
-						m_sQueueSample.field_56 = 0;
-						m_sQueueSample.field_76 = 8;
+						m_sQueueSample.m_bReleasingSoundFlag = false;
+						m_sQueueSample.m_nReleasingVolumeDivider = 8;
 						m_sQueueSample.m_bReverbFlag = 1;
 						m_sQueueSample.m_bRequireReflection = 0;
 						AddSampleToRequestedQueue();
 						return;
 					}
-					accelerationSample = CarSounds[params->m_nIndex].m_nAccelerationSampleIndex;
+					accelerationSample =
+					    CarSounds[params->m_nIndex].m_nAccelerationSampleIndex;
 				}
 				m_sQueueSample.m_nSampleIndex = accelerationSample;
-				m_sQueueSample.m_counter = 2;
+				m_sQueueSample.m_nCounter = 2;
 				m_sQueueSample.m_bBankIndex = 0;
-				m_sQueueSample.m_bIsDistant = 0;
-				m_sQueueSample.field_16 = 3;
-				m_sQueueSample.m_nFrequency = freq + 100 * m_sQueueSample.m_nEntityIndex % 1000;
-				if (m_sQueueSample.m_nSampleIndex == SFX_CAR_IDLE_6 ||
-					m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
-					m_sQueueSample.m_nFrequency = m_sQueueSample.m_nFrequency >> 1;
+				m_sQueueSample.m_bIs2D = 0;
+				m_sQueueSample.m_nReleasingVolumeModificator = 3;
+				m_sQueueSample.m_nFrequency =
+				    freq + 100 * m_sQueueSample.m_nEntityIndex % 1000;
+				if(m_sQueueSample.m_nSampleIndex == SFX_CAR_IDLE_6 ||
+				   m_sQueueSample.m_nSampleIndex == SFX_CAR_REV_6)
+					m_sQueueSample.m_nFrequency =
+					    m_sQueueSample.m_nFrequency >> 1;
 				m_sQueueSample.m_nLoopCount = 0;
 				m_sQueueSample.m_bEmittingVolume = emittingVol;
 				m_sQueueSample.m_nLoopStart =
-					SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.m_nLoopEnd =
-					SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-				m_sQueueSample.field_48 = 6.0f;
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 				m_sQueueSample.m_fSoundIntensity = 50.0f;
-				m_sQueueSample.field_56 = 0;
-				m_sQueueSample.field_76 = 8;
-				m_sQueueSample.m_bReverbFlag = 1;
-				m_sQueueSample.m_bRequireReflection = 0;
+				m_sQueueSample.m_bReleasingSoundFlag = false;
+				m_sQueueSample.m_nReleasingVolumeDivider = 8;
+				m_sQueueSample.m_bReverbFlag = true;
+				m_sQueueSample.m_bRequireReflection = false;
 				AddSampleToRequestedQueue();
 				return;
 			}
@@ -7666,32 +8467,43 @@ cAudioManager::ProcessVehicleHorn(cVehicleParams *params)
 		   automobile->m_modelIndex != MI_MRWHOOP) {
 			if(automobile->m_nCarHornTimer) {
 				if(params->m_pVehicle->m_status) {
-					if(automobile->m_nCarHornTimer > 44) automobile->m_nCarHornTimer = 44;
+					if(automobile->m_nCarHornTimer > 44)
+						automobile->m_nCarHornTimer = 44;
 					if(automobile->m_nCarHornTimer == 44)
 						automobile->field_22D =
-						    (uint8(m_FrameCounter) + uint8(m_sQueueSample.m_nEntityIndex)) & 7;
-					if (!hornPatternsArray[automobile->field_22D][44 - automobile->m_nCarHornTimer]) return;
+						    (uint8(m_FrameCounter) +
+						     uint8(m_sQueueSample.m_nEntityIndex)) &
+						    7;
+					if(!hornPatternsArray[automobile->field_22D]
+					                     [44 - automobile->m_nCarHornTimer])
+						return;
 				}
 
-				CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
-				m_sQueueSample.m_bVolume = ComputeVolume(80, 40.f, m_sQueueSample.m_fDistance);
+				CalculateDistance(params->m_bDistanceCalculated,
+				                  params->m_fDistance);
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(80, 40.f, m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
-					m_sQueueSample.m_counter = 4;
-					m_sQueueSample.m_nSampleIndex = CarSounds[params->m_nIndex].m_nHornSample;
+					m_sQueueSample.m_nCounter = 4;
+					m_sQueueSample.m_nSampleIndex =
+					    CarSounds[params->m_nIndex].m_nHornSample;
 					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-					m_sQueueSample.m_bIsDistant = false;
-					m_sQueueSample.field_16 = 2;
-					m_sQueueSample.m_nFrequency = CarSounds[params->m_nIndex].m_nHornFrequency;
+					m_sQueueSample.m_bIs2D = false;
+					m_sQueueSample.m_nReleasingVolumeModificator = 2;
+					m_sQueueSample.m_nFrequency =
+					    CarSounds[params->m_nIndex].m_nHornFrequency;
 					m_sQueueSample.m_nLoopCount = 0;
 					m_sQueueSample.m_bEmittingVolume = 80;
 					m_sQueueSample.m_nLoopStart =
-					    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopStartOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_nLoopEnd =
-					    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-					m_sQueueSample.field_48 = 5.0f;
+					    SampleManager.GetSampleLoopEndOffset(
+					        m_sQueueSample.m_nSampleIndex);
+					m_sQueueSample.m_fSpeedMultiplier = 5.0f;
 					m_sQueueSample.m_fSoundIntensity = 40.0f;
-					m_sQueueSample.field_56 = 0;
-					m_sQueueSample.field_76 = 3;
+					m_sQueueSample.m_bReleasingSoundFlag = false;
+					m_sQueueSample.m_nReleasingVolumeDivider = 3;
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bRequireReflection = false;
 					AddSampleToRequestedQueue();
@@ -7701,11 +8513,517 @@ cAudioManager::ProcessVehicleHorn(cVehicleParams *params)
 	}
 }
 
-WRAPPER
 void
-cAudioManager::ProcessVehicleOneShots(void *)
+cAudioManager::ProcessVehicleOneShots(cVehicleParams *params)
 {
-	EAXJMP(0x56CD40);
+	int16 event;
+	uint8 emittingVol;
+	float relVol;
+	float vol;
+	bool noReflections;
+	float maxDist;
+	cPedParams pedParams;
+
+	static uint8 WaveIndex = 41;
+	static uint8 GunIndex = 53;
+	static uint8 iWheelIndex = 82;
+	static uint8 CrunchOffset = 0;
+
+	for(int i = 0; i < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_AudioEvents; i++) {
+		noReflections = 0;
+		m_sQueueSample.m_bRequireReflection = false;
+		event = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i];
+		switch(event) {
+		case SOUND_CAR_DOOR_CLOSE_BONNET:
+		case SOUND_CAR_DOOR_CLOSE_BUMPER:
+		case SOUND_CAR_DOOR_CLOSE_FRONT_LEFT:
+		case SOUND_CAR_DOOR_CLOSE_FRONT_RIGHT:
+		case SOUND_CAR_DOOR_CLOSE_BACK_LEFT:
+		case SOUND_CAR_DOOR_CLOSE_BACK_RIGHT:
+			maxDist = 2500.f;
+			emittingVol = m_anRandomTable[2] % 5 + 122;
+			switch(CarSounds[params->m_nIndex].m_bDoorType) {
+			case 0: m_sQueueSample.m_nSampleIndex = SFX_OLD_CAR_DOOR_CLOSE; break;
+			case 2: m_sQueueSample.m_nSampleIndex = SFX_TRUCK_DOOR_CLOSE; break;
+			case 3: m_sQueueSample.m_nSampleIndex = SFX_AIR_BRAKES; break;
+			default: m_sQueueSample.m_nSampleIndex = SFX_NEW_CAR_DOOR_CLOSE; break;
+			}
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter =
+			    m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 22;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 50.0f;
+			m_sQueueSample.m_bRequireReflection = true;
+			break;
+		case SOUND_CAR_DOOR_OPEN_BONNET:
+		case SOUND_CAR_DOOR_OPEN_BUMPER:
+		case SOUND_CAR_DOOR_OPEN_FRONT_LEFT:
+		case SOUND_CAR_DOOR_OPEN_FRONT_RIGHT:
+		case SOUND_CAR_DOOR_OPEN_BACK_LEFT:
+		case SOUND_CAR_DOOR_OPEN_BACK_RIGHT:
+			maxDist = 2500.f;
+			emittingVol = m_anRandomTable[1] % 10 + 117;
+			switch(CarSounds[params->m_nIndex].m_bDoorType) {
+			case 0: m_sQueueSample.m_nSampleIndex = SFX_OLD_CAR_DOOR_OPEN; break;
+			case 2: m_sQueueSample.m_nSampleIndex = SFX_TRUCK_DOOR_OPEN; break;
+			case 3: m_sQueueSample.m_nSampleIndex = SFX_AIR_BRAKES; break;
+			default: m_sQueueSample.m_nSampleIndex = SFX_NEW_CAR_DOOR_OPEN; break;
+			}
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter =
+			    m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 10;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 50.0f;
+			m_sQueueSample.m_bRequireReflection = true;
+			break;
+		case SOUND_CAR_WINDSHIELD_CRACK:
+			maxDist = 900.f;
+			m_sQueueSample.m_nSampleIndex = SFX_GLASS_CRACK;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 68;
+			emittingVol = m_anRandomTable[1] % 30 + 60;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_GLASS_CRACK);
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 30.0f;
+			break;
+		case SOUND_CAR_JUMP:
+			emittingVol = max(
+			    80.f,
+			    2 * (100.f *
+			         m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_afVolume[i]));
+			maxDist = 1225.f;
+			m_sQueueSample.m_nSampleIndex = SFX_TYRE_BUMP;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = iWheelIndex++;
+			if(iWheelIndex > 85) iWheelIndex = 82;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_TYRE_BUMP);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+			if(params->m_nIndex == 41) {
+				m_sQueueSample.m_nFrequency *= 2;
+				emittingVol = emittingVol >> 1;
+			}
+			m_sQueueSample.m_nReleasingVolumeModificator = 6;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+			m_sQueueSample.m_fSoundIntensity = 35.0f;
+			break;
+		case SOUND_E:
+		case SOUND_F:
+		case SOUND_STEP_START:
+		case SOUND_STEP_END:
+		case SOUND_FALL_LAND:
+		case SOUND_FALL_COLLAPSE:
+		case SOUND_FIGHT_PUNCH_33:
+		case SOUND_FIGHT_KICK_34:
+		case SOUND_FIGHT_HEADBUTT_35:
+		case SOUND_FIGHT_PUNCH_36:
+		case SOUND_FIGHT_PUNCH_37:
+		case SOUND_FIGHT_CLOSE_PUNCH_38:
+		case SOUND_FIGHT_PUNCH_39:
+		case SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40:
+		case SOUND_FIGHT_PUNCH_41:
+		case SOUND_FIGHT_PUNCH_FROM_BEHIND_42:
+		case SOUND_FIGHT_KNEE_OR_KICK_43:
+		case SOUND_FIGHT_KICK_44:
+		case SOUND_WEAPON_BAT_ATTACK:
+		case SOUND_WEAPON_RELOAD:
+		case SOUND_WEAPON_AK47_BULLET_ECHO:
+		case SOUND_WEAPON_UZI_BULLET_ECHO:
+		case SOUND_WEAPON_M16_BULLET_ECHO:
+		case SOUND_WEAPON_FLAMETHROWER_FIRE:
+		case SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM:
+		case SOUND_WEAPON_ROCKET_SHOT_NO_ZOOM:
+		case SOUND_WEAPON_HIT_PED:
+		case SOUND_GARAGE_NO_MONEY:
+		case SOUND_GARAGE_BAD_VEHICLE:
+		case SOUND_GARAGE_OPENING:
+		case SOUND_GARAGE_BOMB_ALREADY_SET:
+		case SOUND_GARAGE_BOMB1_SET:
+		case SOUND_GARAGE_BOMB2_SET:
+		case SOUND_GARAGE_BOMB3_SET:
+		case SOUND_40:
+		case SOUND_41:
+		case SOUND_GARAGE_VEHICLE_DECLINED:
+		case SOUND_GARAGE_VEHICLE_ACCEPTED:
+		case SOUND_GARAGE_DOOR_CLOSED:
+		case SOUND_GARAGE_DOOR_OPENED:
+		case SOUND_CRANE_PICKUP:
+		case SOUND_PICKUP_WEAPON_BOUGHT:
+		case SOUND_PICKUP_WEAPON:
+		case SOUND_PICKUP_HEALTH:
+		case SOUND_4A:
+		case SOUND_4B:
+		case SOUND_PICKUP_ADRENALINE:
+		case SOUND_PICKUP_ARMOUR:
+		case SOUND_PICKUP_BONUS:
+		case SOUND_PICKUP_MONEY:
+		case SOUND_PICKUP_HIDDEN_PACKAGE:
+		case SOUND_PICKUP_PACMAN_PILL:
+		case SOUND_PICKUP_PACMAN_PACKAGE:
+		case SOUND_PICKUP_FLOAT_PACKAGE:
+		case SOUND_RAMPAGE_START:
+		case SOUND_RAMPAGE_ONGOING:
+		case SOUND_RAMPAGE_PASSED:
+		case SOUND_RAMPAGE_FAILED:
+		case SOUND_RAMPAGE_KILL:
+		case SOUND_RAMPAGE_CAR_BLOWN:
+		case SOUND_EVIDENCE_PICKUP:
+		case SOUND_UNLOAD_GOLD:
+		case SOUND_PAGER:
+		case SOUND_PED_DEATH:
+		case SOUND_PED_DAMAGE:
+		case SOUND_PED_HIT:
+		case SOUND_PED_LAND:
+		case SOUND_PED_BULLET_HIT:
+		case SOUND_PED_BOMBER:
+		case SOUND_PED_BURNING:
+		case SOUND_PED_ARREST_FBI:
+		case SOUND_PED_ARREST_SWAT:
+		case SOUND_PED_ARREST_COP:
+		case SOUND_PED_HANDS_UP:
+		case SOUND_PED_HANDS_COWER:
+		case SOUND_PED_FLEE_SPRINT:
+		case SOUND_PED_CAR_JACKING:
+		case SOUND_PED_MUGGING:
+		case SOUND_PED_CAR_JACKED:
+		case SOUND_PED_ROBBED:
+		case SOUND_PED_TAXI_WAIT:
+		case SOUND_PED_ATTACK:
+		case SOUND_PED_DEFEND:
+		case SOUND_PED_PURSUIT_ARMY:
+		case SOUND_PED_PURSUIT_FBI:
+		case SOUND_PED_PURSUIT_SWAT:
+		case SOUND_PED_PURSUIT_COP:
+		case SOUND_PED_HEALING:
+		case SOUND_PED_7B:
+		case SOUND_PED_LEAVE_VEHICLE:
+		case SOUND_PED_EVADE:
+		case SOUND_PED_FLEE_RUN:
+		case SOUND_PED_CAR_COLLISION:
+		case SOUND_PED_SOLICIT:
+		case SOUND_PED_EXTINGUISHING_FIRE:
+		case SOUND_PED_WAIT_DOUBLEBACK:
+		case SOUND_PED_CHAT_SEXY:
+		case SOUND_PED_CHAT_EVENT:
+		case SOUND_PED_CHAT:
+		case SOUND_PED_TAXI_CALL:
+		case SOUND_INJURED_PED_MALE_OUCH:
+		case SOUND_INJURED_PED_FEMALE:
+		case SOUND_8A:
+		case SOUND_RACE_START_3:
+		case SOUND_RACE_START_2:
+		case SOUND_RACE_START_1:
+		case SOUND_RACE_START_GO:
+		case SOUND_SPLASH: continue;
+		case SOUND_CAR_ENGINE_START:
+			emittingVol = 60;
+			maxDist = 1600.f;
+			m_sQueueSample.m_nSampleIndex = SFX_CAR_STARTER;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 33;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_CAR_STARTER);
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+			m_sQueueSample.m_fSoundIntensity = 40.0f;
+			m_sQueueSample.m_bRequireReflection = true;
+			break;
+		case SOUND_CAR_LIGHT_BREAK:
+			m_sQueueSample.m_nSampleIndex = SFX_GLASS_SHARD_1;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 37;
+			m_sQueueSample.m_nFrequency =
+			    9 * SampleManager.GetSampleBaseFrequency(SFX_GLASS_SHARD_1) / 10;
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 30.0f;
+			maxDist = 900.f;
+			emittingVol = m_anRandomTable[4] % 10 + 30;
+			break;
+		case SOUND_CAR_HYDRAULIC_1:
+		case SOUND_CAR_HYDRAULIC_2:
+			if(event == MOONBEAM) // todo check
+				m_sQueueSample.m_nFrequency = 15600;
+			else
+				m_sQueueSample.m_nFrequency = 13118;
+			m_sQueueSample.m_nSampleIndex = SFX_SUSPENSION_FAST_MOVE;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 51;
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 35.0f;
+			maxDist = 1225.f;
+			emittingVol = m_anRandomTable[0] % 15 + 55;
+			break;
+		case SOUND_CAR_HYDRAULIC_3:
+			m_sQueueSample.m_nSampleIndex = SFX_SUSPENSION_SLOW_MOVE_LOOP;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 86;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_SUSPENSION_SLOW_MOVE_LOOP);
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 35.0f;
+			m_sQueueSample.m_nReleasingVolumeDivider = 7;
+			noReflections = true;
+			maxDist = 1225.f;
+			emittingVol = m_anRandomTable[0] % 15 + 55;
+			break;
+		case SOUND_CAR_JERK:
+			m_sQueueSample.m_nSampleIndex = SFX_SHAG_SUSPENSION;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 87;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_SHAG_SUSPENSION);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 3);
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 35.0f;
+			maxDist = 1225.f;
+			emittingVol = m_anRandomTable[1] % 15 + 55;
+			break;
+		case SOUND_CAR_SPLASH:
+			vol = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_afVolume[i];
+			if(vol <= 300.f) continue;
+			if(vol > 1200.f)
+				m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_afVolume[i] =
+				    1200.0f;
+			relVol = (m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_afVolume[i] -
+			          300.f) /
+			         900.f;
+			m_sQueueSample.m_nSampleIndex =
+			    (m_anRandomTable[0] & 1) + SFX_BOAT_SPLASH_1;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = WaveIndex++;
+			if(WaveIndex > 46) WaveIndex = 41;
+			m_sQueueSample.m_nFrequency = (7000.f * relVol) + 6000;
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+			m_sQueueSample.m_fSoundIntensity = 40.0f;
+			emittingVol = (55.f * relVol);
+			maxDist = 1600.f;
+			break;
+		case SOUND_17:
+			m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_THUMB_OFF;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 47;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_POLICE_BOAT_THUMB_OFF) +
+			    RandomDisplacement(600);
+			m_sQueueSample.m_nReleasingVolumeModificator = 2;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 50.0f;
+			emittingVol =
+			    m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_afVolume[i];
+			maxDist = 2500.f;
+			break;
+		case SOUND_18:
+		case SOUND_19:
+			m_sQueueSample.m_nSampleIndex = SFX_AIR_BRAKES;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 59;
+			m_sQueueSample.m_nFrequency = RandomDisplacement(1000) + 11025;
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 5.0f;
+			m_sQueueSample.m_fSoundIntensity = 35.0f;
+			maxDist = 1225.f;
+			emittingVol = m_anRandomTable[1] % 20 + 70;
+			break;
+		case SOUND_CAR_TANK_TURRET_ROTATE:
+			vol = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_afVolume[i];
+			if(vol > 0.038400002f) vol = 0.038400002f;
+			m_sQueueSample.m_nSampleIndex = SFX_TANK_TURRET;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 79;
+			m_sQueueSample.m_nFrequency = (3000.f * vol * 26.041666f) + 9000;
+			m_sQueueSample.m_nReleasingVolumeModificator = 2;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
+			m_sQueueSample.m_fSoundIntensity = 40.0f;
+			emittingVol = (37.f * vol * 26.041666f) + 90;
+			maxDist = 1600.f;
+			noReflections = true;
+			break;
+		case SOUND_CAR_BOMB_TICK:
+			m_sQueueSample.m_nSampleIndex = SFX_BOMB_BEEP;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 80;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_BOMB_BEEP);
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 30.0f;
+			maxDist = 900.f;
+			m_sQueueSample.m_bRequireReflection = true;
+			emittingVol = 60;
+			break;
+		case SOUND_PLANE_ON_GROUND:
+			m_sQueueSample.m_nSampleIndex = SFX_JUMBO_LAND_WHEELS;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 81;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_JUMBO_LAND_WHEELS);
+			m_sQueueSample.m_nReleasingVolumeModificator = 2;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 180.0f;
+			maxDist = 32400.f;
+			emittingVol = m_anRandomTable[4] % 25 + 75;
+			break;
+		case SOUND_WEAPON_SHOT_FIRED:
+			emittingVol = m_anRandomTable[2];
+			maxDist = 14400.f;
+			m_sQueueSample.m_nSampleIndex = SFX_UZI_LEFT;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = GunIndex++;
+			emittingVol = emittingVol % 15 + 65;
+			if(GunIndex > 58) GunIndex = 53;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_UZI_LEFT);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 4);
+			m_sQueueSample.m_nReleasingVolumeModificator = 3;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 120.0f;
+			break;
+		case SOUND_WEAPON_HIT_VEHICLE:
+			m_sQueueSample.m_nSampleIndex =
+			    m_anRandomTable[m_sQueueSample.m_nEntityIndex %
+			                    ARRAY_SIZE(m_anRandomTable)] %
+			        6 +
+			    SFX_BULLET_CAR_1;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 34;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nFrequency +=
+			    RandomDisplacement(m_sQueueSample.m_nFrequency >> 5);
+			m_sQueueSample.m_nReleasingVolumeModificator = 7;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 40.0f;
+			maxDist = 1600.f;
+			emittingVol = m_anRandomTable[3] % 20 + 90;
+			break;
+		case SOUND_BOMB_TIMED_ACTIVATED:
+		case SOUND_55:
+		case SOUND_BOMB_ONIGNITION_ACTIVATED:
+		case SOUND_BOMB_TICK:
+			m_sQueueSample.m_nSampleIndex = SFX_ARM_BOMB;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 36;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_ARM_BOMB);
+			m_sQueueSample.m_nReleasingVolumeModificator = 0;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 50.0f;
+			m_sQueueSample.m_bRequireReflection = true;
+			emittingVol = 50;
+			maxDist = 2500.f;
+			break;
+		case SOUND_PED_HELI_PLAYER_FOUND:
+			pedParams.m_pPed = 0;
+			pedParams.m_bDistanceCalculated = 0;
+			pedParams.m_fDistance = 0.0f;
+			pedParams.m_bDistanceCalculated = params->m_bDistanceCalculated;
+			pedParams.m_fDistance = params->m_fDistance;
+			SetupPedComments(&pedParams, SOUND_PED_HELI_PLAYER_FOUND);
+			continue;
+		case SOUND_PED_BODYCAST_HIT:
+			pedParams.m_pPed = 0;
+			pedParams.m_bDistanceCalculated = 0;
+			pedParams.m_fDistance = 0.0f;
+			pedParams.m_bDistanceCalculated = params->m_bDistanceCalculated;
+			pedParams.m_fDistance = params->m_fDistance;
+			SetupPedComments(&pedParams, SOUND_PED_BODYCAST_HIT);
+			continue;
+		case SOUND_WATER_FALL:
+			m_sQueueSample.m_nSampleIndex = SFX_SPLASH_1;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 15;
+			m_sQueueSample.m_nFrequency = RandomDisplacement(1000) + 16000;
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 40.0f;
+			maxDist = 1600.f;
+			m_sQueueSample.m_bRequireReflection = true;
+			emittingVol = m_anRandomTable[4] % 20 + 90;
+			break;
+		case SOUND_SPLATTER:
+			m_sQueueSample.m_nSampleIndex = CrunchOffset + SFX_PED_CRUNCH_1;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 48;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_PED_CRUNCH_1) +
+			    RandomDisplacement(600);
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 40.0f;
+			++CrunchOffset;
+			maxDist = 1600.f;
+			emittingVol = m_anRandomTable[4] % 20 + 55;
+			CrunchOffset &= 1u;
+			m_sQueueSample.m_bRequireReflection = true;
+			break;
+		case SOUND_CAR_PED_COLLISION:
+			vol = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_afVolume[i];
+			if(20.f < vol) vol = 20.f;
+			emittingVol = (vol * 0.05f * 127.f);
+			if(!emittingVol) continue;
+
+			m_sQueueSample.m_nSampleIndex = (m_anRandomTable[2] & 3) + SFX_FIGHT_1;
+			m_sQueueSample.m_bBankIndex = 0;
+			m_sQueueSample.m_nCounter = 50;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex) >>
+			    1;
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
+			m_sQueueSample.m_fSpeedMultiplier = 0.0f;
+			m_sQueueSample.m_fSoundIntensity = 40.0f;
+			maxDist = 1600.f;
+			break;
+		}
+		if(params->m_fDistance < maxDist) {
+			CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
+			m_sQueueSample.m_bVolume =
+			    ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity,
+			                  m_sQueueSample.m_fDistance);
+			if(m_sQueueSample.m_bVolume) {
+				if(noReflections) {
+					m_sQueueSample.m_nLoopCount = 0;
+					m_sQueueSample.m_bReleasingSoundFlag = 0;
+				} else {
+					m_sQueueSample.m_nLoopCount = 1;
+					m_sQueueSample.m_bReleasingSoundFlag = 1;
+				}
+				m_sQueueSample.m_nLoopStart =
+				    SampleManager.GetSampleLoopStartOffset(
+				        m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(
+				    m_sQueueSample.m_nSampleIndex);
+				m_sQueueSample.m_bEmittingVolume = emittingVol;
+				m_sQueueSample.m_bReverbFlag = 1;
+				m_sQueueSample.m_bIs2D = false;
+				AddSampleToRequestedQueue();
+			}
+		}
+	}
 }
 
 bool
@@ -7719,11 +9037,11 @@ cAudioManager::ProcessVehicleReverseWarning(cVehicleParams *params)
 		CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 		m_sQueueSample.m_bVolume = ComputeVolume(60, 50.f, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 12;
+			m_sQueueSample.m_nCounter = 12;
 			m_sQueueSample.m_nSampleIndex = SFX_REVERSE_WARNING;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 2;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 2;
 			m_sQueueSample.m_nFrequency =
 			    (100 * m_sQueueSample.m_nEntityIndex & 1023) +
 			    SampleManager.GetSampleBaseFrequency(SFX_REVERSE_WARNING);
@@ -7731,11 +9049,12 @@ cAudioManager::ProcessVehicleReverseWarning(cVehicleParams *params)
 			m_sQueueSample.m_bEmittingVolume = 60;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 3.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 3.0f;
 			m_sQueueSample.m_fSoundIntensity = 50.0f;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 3;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -7758,16 +9077,21 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params)
 		if(params->m_pVehicle->m_vecMoveSpeed.z) {
 			velocity = Abs(params->m_fVelocityChange);
 			if(velocity > 0.0f) {
-				CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
+				CalculateDistance(params->m_bDistanceCalculated,
+				                  params->m_fDistance);
 				emittingVol =
-				    30.f * min(1.f, velocity / (0.5f * params->m_pTransmission->fMaxVelocity));
-				m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 95.f, m_sQueueSample.m_fDistance);
+				    30.f *
+				    min(1.f,
+				        velocity / (0.5f * params->m_pTransmission->fMaxVelocity));
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(emittingVol, 95.f, m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
-					m_sQueueSample.m_counter = 0;
+					m_sQueueSample.m_nCounter = 0;
 					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-					m_sQueueSample.m_bIsDistant = false;
-					m_sQueueSample.field_16 = 3;
-					if(params->m_pVehicle->m_nSurfaceTouched == SURFACE_PUDDLE) {
+					m_sQueueSample.m_bIs2D = false;
+					m_sQueueSample.m_nReleasingVolumeModificator = 3;
+					if(params->m_pVehicle->m_nSurfaceTouched ==
+					   SURFACE_PUDDLE) {
 						m_sQueueSample.m_nSampleIndex = SFX_BOAT_WATER_LOOP;
 						freq = 6050 * emittingVol / 30 + 16000;
 					} else {
@@ -7775,19 +9099,22 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params)
 						modificator = m_sQueueSample.m_fDistance / 190.f;
 						sampleFreq = SampleManager.GetSampleBaseFrequency(
 						    SFX_ROAD_NOISE);
-						freq = (sampleFreq * modificator) + ((3 * sampleFreq) >> 2);
+						freq = (sampleFreq * modificator) +
+						       ((3 * sampleFreq) >> 2);
 					}
 					m_sQueueSample.m_nFrequency = freq;
 					m_sQueueSample.m_nLoopCount = 0;
 					m_sQueueSample.m_bEmittingVolume = emittingVol;
 					m_sQueueSample.m_nLoopStart =
-					    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopStartOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_nLoopEnd =
-					    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-					m_sQueueSample.field_48 = 6.0f;
+					    SampleManager.GetSampleLoopEndOffset(
+					        m_sQueueSample.m_nSampleIndex);
+					m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 					m_sQueueSample.m_fSoundIntensity = 95.0f;
-					m_sQueueSample.field_56 = 0;
-					m_sQueueSample.field_76 = 4;
+					m_sQueueSample.m_bReleasingSoundFlag = false;
+					m_sQueueSample.m_nReleasingVolumeDivider = 4;
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bRequireReflection = false;
 					AddSampleToRequestedQueue();
@@ -7808,7 +9135,7 @@ cAudioManager::ProcessVehicleSirenOrAlarm(cVehicleParams *params)
 		CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 		m_sQueueSample.m_bVolume = ComputeVolume(80, 110.f, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 5;
+			m_sQueueSample.m_nCounter = 5;
 			if(UsesSiren(params->m_nIndex)) {
 				if(params->m_pVehicle->m_status == STATUS_ABANDONED) return;
 				if(veh->m_nCarHornTimer && params->m_nIndex != FIRETRUK) {
@@ -7817,8 +9144,9 @@ cAudioManager::ProcessVehicleSirenOrAlarm(cVehicleParams *params)
 						m_sQueueSample.m_nFrequency = 16113;
 					else
 						m_sQueueSample.m_nFrequency =
-						    SampleManager.GetSampleBaseFrequency(SFX_SIREN_FAST);
-					m_sQueueSample.m_counter = 60;
+						    SampleManager.GetSampleBaseFrequency(
+						        SFX_SIREN_FAST);
+					m_sQueueSample.m_nCounter = 60;
 				} else {
 					m_sQueueSample.m_nSampleIndex =
 					    CarSounds[params->m_nIndex].m_nSirenOrAlarmSample;
@@ -7826,21 +9154,24 @@ cAudioManager::ProcessVehicleSirenOrAlarm(cVehicleParams *params)
 					    CarSounds[params->m_nIndex].m_nSirenOrAlarmFrequency;
 				}
 			} else {
-				m_sQueueSample.m_nSampleIndex = CarSounds[params->m_nIndex].m_nSirenOrAlarmSample;
-				m_sQueueSample.m_nFrequency = CarSounds[params->m_nIndex].m_nSirenOrAlarmFrequency;
+				m_sQueueSample.m_nSampleIndex =
+				    CarSounds[params->m_nIndex].m_nSirenOrAlarmSample;
+				m_sQueueSample.m_nFrequency =
+				    CarSounds[params->m_nIndex].m_nSirenOrAlarmFrequency;
 			}
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 1;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 1;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = 80;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 7.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 7.0f;
 			m_sQueueSample.m_fSoundIntensity = 110.0f;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 5;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 5;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -7863,12 +9194,13 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params)
 	if(!automobile->m_nWheelsOnGround) return;
 	CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
 	for(int32 i = 0; i < ARRAY_SIZE(automobile->m_aWheelState); i++) {
-		if(!automobile->m_aWheelState[i] || automobile->Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING)
+		if(!automobile->m_aWheelState[i] ||
+		   automobile->Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING)
 			continue;
 		transmission = params->m_pTransmission;
 		if(transmission->nDriveType == '4') {
-			newSkidVal =
-			    GetVehicleDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange);
+			newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission,
+			                                           params->m_fVelocityChange);
 			if(newSkidVal > skidVal) skidVal = newSkidVal;
 			continue;
 		}
@@ -7878,31 +9210,33 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params)
 				continue;
 			}
 			if(i != 1 && i != 3) {
-				newSkidVal = GetVehicleNonDriveWheelSkidValue(i, automobile, transmission,
-				                                              params->m_fVelocityChange);
+				newSkidVal = GetVehicleNonDriveWheelSkidValue(
+				    i, automobile, transmission, params->m_fVelocityChange);
 				if(newSkidVal > skidVal) skidVal = newSkidVal;
 				continue;
 			}
-			newSkidVal =
-			    GetVehicleDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange);
+			newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission,
+			                                           params->m_fVelocityChange);
 			if(newSkidVal > skidVal) skidVal = newSkidVal;
 			continue;
 		}
 		if(i == 0 || i == 2) {
-			newSkidVal =
-			    GetVehicleDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange);
+			newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission,
+			                                           params->m_fVelocityChange);
 			if(newSkidVal > skidVal) skidVal = newSkidVal;
 			continue;
 		}
-		newSkidVal = GetVehicleNonDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange);
+		newSkidVal = GetVehicleNonDriveWheelSkidValue(i, automobile, transmission,
+		                                              params->m_fVelocityChange);
 		if(newSkidVal > skidVal) skidVal = newSkidVal;
 	}
 
 	if(skidVal > 0.0f) {
 		emittingVol = 50.f * skidVal;
-		m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 40.f, m_sQueueSample.m_fDistance);
+		m_sQueueSample.m_bVolume =
+		    ComputeVolume(emittingVol, 40.f, m_sQueueSample.m_fDistance);
 		if(m_sQueueSample.m_bVolume) {
-			m_sQueueSample.m_counter = 3;
+			m_sQueueSample.m_nCounter = 3;
 			switch(params->m_pVehicle->m_nSurfaceTouched) {
 			case SURFACE_GRASS:
 			case SURFACE_HEDGE:
@@ -7926,17 +9260,18 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params)
 			}
 
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_bIsDistant = false;
-			m_sQueueSample.field_16 = 8;
+			m_sQueueSample.m_bIs2D = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 8;
 			m_sQueueSample.m_nLoopCount = 0;
 			m_sQueueSample.m_bEmittingVolume = emittingVol;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.field_48 = 3.0f;
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_fSpeedMultiplier = 3.0f;
 			m_sQueueSample.m_fSoundIntensity = 40.0f;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_76 = 3;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeDivider = 3;
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -7948,29 +9283,33 @@ void cAudioManager::ProcessWaterCannon(int32)
 {
 	for(int32 i = 0; i < NUM_WATERCANNONS; i++) {
 		if(CWaterCannons::aCannons[i].m_nId) {
-			m_sQueueSample.m_vecPos = CWaterCannons::aCannons[0].m_avecPos[CWaterCannons::aCannons[i].m_nCur];
+			m_sQueueSample.m_vecPos =
+			    CWaterCannons::aCannons[0].m_avecPos[CWaterCannons::aCannons[i].m_nCur];
 			float distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
 			if(distSquared < 900.f) {
 				m_sQueueSample.m_fDistance = Sqrt(distSquared);
 				m_sQueueSample.m_bVolume =
-				    ComputeVolume(50, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance);
+				    ComputeVolume(50, m_sQueueSample.m_fSoundIntensity,
+				                  m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
 					m_sQueueSample.m_fSoundIntensity = 900.0f;
 					m_sQueueSample.m_nSampleIndex = SFX_JUMBO_TAXI;
 					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
 					m_sQueueSample.m_nFrequency = 15591;
-					m_sQueueSample.field_16 = 5;
-					m_sQueueSample.m_counter = i;
-					m_sQueueSample.field_48 = 2.0f;
-					m_sQueueSample.field_76 = 8;
-					m_sQueueSample.m_bIsDistant = false;
+					m_sQueueSample.m_nReleasingVolumeModificator = 5;
+					m_sQueueSample.m_nCounter = i;
+					m_sQueueSample.m_fSpeedMultiplier = 2.0f;
+					m_sQueueSample.m_nReleasingVolumeDivider = 8;
+					m_sQueueSample.m_bIs2D = false;
 					m_sQueueSample.m_nLoopCount = 0;
-					m_sQueueSample.field_56 = 0;
+					m_sQueueSample.m_bReleasingSoundFlag = false;
 					m_sQueueSample.m_bEmittingVolume = 50;
 					m_sQueueSample.m_nLoopStart =
-					    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopStartOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_nLoopEnd =
-					    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopEndOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bRequireReflection = false;
 					AddSampleToRequestedQueue();
@@ -7986,7 +9325,8 @@ cAudioManager::ProcessWeather(int32 id)
 	uint8 vol;
 	static uint8 counter = 0;
 
-	if(m_asAudioEntities[id].m_AudioEvents && m_asAudioEntities[id].m_awAudioEvent[0] == SOUND_LIGHTNING) {
+	if(m_asAudioEntities[id].m_AudioEvents &&
+	   m_asAudioEntities[id].m_awAudioEvent[0] == SOUND_LIGHTNING) {
 		if(m_asAudioEntities[id].m_afVolume[0] >= 10.f) {
 			m_sQueueSample.m_nSampleIndex = SFX_EXPLOSION_1;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
@@ -8001,12 +9341,12 @@ cAudioManager::ProcessWeather(int32 id)
 		m_sQueueSample.m_bVolume = vol;
 		if(TheCamera.SoundDistUp < 20.f) m_sQueueSample.m_bVolume >>= 1;
 		if(counter == 4) counter = 0;
-		m_sQueueSample.m_counter = counter++;
-		m_sQueueSample.field_16 = 0;
+		m_sQueueSample.m_nCounter = counter++;
+		m_sQueueSample.m_nReleasingVolumeModificator = 0;
 		m_sQueueSample.m_bOffset = (m_anRandomTable[2] & 15) + 55;
-		m_sQueueSample.m_bIsDistant = true;
+		m_sQueueSample.m_bIs2D = true;
 		m_sQueueSample.m_nLoopCount = 1;
-		m_sQueueSample.field_56 = 1;
+		m_sQueueSample.m_bReleasingSoundFlag = true;
 		m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume;
 		m_sQueueSample.m_nLoopStart = 0;
 		m_sQueueSample.m_nLoopEnd = -1;
@@ -8016,21 +9356,22 @@ cAudioManager::ProcessWeather(int32 id)
 	}
 	if(CWeather::Rain > 0.0f && (!CCullZones::CamNoRain() || !CCullZones::PlayerNoRain())) {
 		m_sQueueSample.m_nSampleIndex = SFX_RAIN;
-		m_sQueueSample.m_nFrequency =
-		    SampleManager.GetSampleBaseFrequency(SFX_RAIN);
+		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_RAIN);
 		m_sQueueSample.m_bVolume = (int32)(25.f * CWeather::Rain);
-		m_sQueueSample.m_counter = 4;
+		m_sQueueSample.m_nCounter = 4;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.field_16 = 0;
+		m_sQueueSample.m_nReleasingVolumeModificator = 0;
 		m_sQueueSample.m_bOffset = 63;
-		m_sQueueSample.m_bIsDistant = true;
+		m_sQueueSample.m_bIs2D = true;
 		m_sQueueSample.m_nLoopCount = 0;
-		m_sQueueSample.field_56 = 0;
-		m_sQueueSample.field_76 = 30;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
+		m_sQueueSample.m_nReleasingVolumeDivider = 30;
 		m_sQueueSample.m_bReverbFlag = false;
 		m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume;
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
 	}
@@ -8050,30 +9391,35 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params)
 		if(params->m_pVehicle->m_vecMoveSpeed.z) {
 			velChange = Abs(params->m_fVelocityChange);
 			if(velChange > 0.f) {
-				CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance);
+				CalculateDistance(params->m_bDistanceCalculated,
+				                  params->m_fDistance);
 				relativeVelocity =
-				    min(1.0f, velChange / (0.5f * params->m_pTransmission->fMaxVelocity));
+				    min(1.0f,
+				        velChange / (0.5f * params->m_pTransmission->fMaxVelocity));
 				emittingVol = 23.0f * relativeVelocity * CWeather::WetRoads;
-				m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 30.f, m_sQueueSample.m_fDistance);
+				m_sQueueSample.m_bVolume =
+				    ComputeVolume(emittingVol, 30.f, m_sQueueSample.m_fDistance);
 				if(m_sQueueSample.m_bVolume) {
-					m_sQueueSample.m_counter = 1;
+					m_sQueueSample.m_nCounter = 1;
 					m_sQueueSample.m_nSampleIndex = SFX_ROAD_NOISE;
 					m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-					m_sQueueSample.m_bIsDistant = false;
-					m_sQueueSample.field_16 = 3;
+					m_sQueueSample.m_bIs2D = false;
+					m_sQueueSample.m_nReleasingVolumeModificator = 3;
 					modificator = m_sQueueSample.m_fDistance / 6.f;
 					freq = SampleManager.GetSampleBaseFrequency(SFX_ROAD_NOISE);
 					m_sQueueSample.m_nFrequency = freq + freq * modificator;
 					m_sQueueSample.m_nLoopCount = 0;
 					m_sQueueSample.m_bEmittingVolume = emittingVol;
 					m_sQueueSample.m_nLoopStart =
-					    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+					    SampleManager.GetSampleLoopStartOffset(
+					        m_sQueueSample.m_nSampleIndex);
 					m_sQueueSample.m_nLoopEnd =
-					    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-					m_sQueueSample.field_48 = 6.0f;
+					    SampleManager.GetSampleLoopEndOffset(
+					        m_sQueueSample.m_nSampleIndex);
+					m_sQueueSample.m_fSpeedMultiplier = 6.0f;
 					m_sQueueSample.m_fSoundIntensity = 30.0f;
-					m_sQueueSample.field_56 = 0;
-					m_sQueueSample.field_76 = 4;
+					m_sQueueSample.m_bReleasingSoundFlag = false;
+					m_sQueueSample.m_nReleasingVolumeDivider = 4;
 					m_sQueueSample.m_bReverbFlag = true;
 					m_sQueueSample.m_bRequireReflection = false;
 					AddSampleToRequestedQueue();
@@ -8091,9 +9437,7 @@ cAudioManager::ProcessWorkShopScriptObject(uint8 sound)
 
 	switch(sound) {
 	case SCRIPT_SOUND_WORK_SHOP_LOOP_S:
-	case SCRIPT_SOUND_WORK_SHOP_LOOP_L:
-		m_sQueueSample.m_fSoundIntensity = 20.0f;
-		break;
+	case SCRIPT_SOUND_WORK_SHOP_LOOP_L: m_sQueueSample.m_fSoundIntensity = 20.0f; break;
 	default: return;
 	}
 	distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
@@ -8104,17 +9448,19 @@ cAudioManager::ProcessWorkShopScriptObject(uint8 sound)
 		if(m_sQueueSample.m_bVolume) {
 			m_sQueueSample.m_nSampleIndex = SFX_WORKSHOP_1;
 			m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-			m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_WORKSHOP_1);
-			m_sQueueSample.m_counter = 0;
-			m_sQueueSample.m_bIsDistant = false;
+			m_sQueueSample.m_nFrequency =
+			    SampleManager.GetSampleBaseFrequency(SFX_WORKSHOP_1);
+			m_sQueueSample.m_nCounter = 0;
+			m_sQueueSample.m_bIs2D = false;
 			m_sQueueSample.m_nLoopCount = 0;
-			m_sQueueSample.field_56 = 0;
-			m_sQueueSample.field_16 = 5;
-			m_sQueueSample.field_48 = 2.0f;
+			m_sQueueSample.m_bReleasingSoundFlag = false;
+			m_sQueueSample.m_nReleasingVolumeModificator = 5;
+			m_sQueueSample.m_fSpeedMultiplier = 2.0f;
 			m_sQueueSample.m_bEmittingVolume = 30;
 			m_sQueueSample.m_nLoopStart =
 			    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-			m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+			m_sQueueSample.m_nLoopEnd =
+			    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 			m_sQueueSample.m_bReverbFlag = true;
 			m_sQueueSample.m_bRequireReflection = false;
 			AddSampleToRequestedQueue();
@@ -8223,15 +9569,10 @@ cAudioManager::Service()
 void
 cAudioManager::ServiceSoundEffects()
 {
-	uint32 timeOfRecentCrime;
-	cAudioScriptObject *object;
-
-	timeOfRecentCrime = m_FrameCounter;
-	++m_FrameCounter;
-	if(timeOfRecentCrime % 5)
-		field_2 = 0;
+	if(m_FrameCounter++ % 5)
+		m_bFifthFrameFlag = false;
 	else
-		field_2 = 1;
+		m_bFifthFrameFlag = true;
 	if(m_bUserPause && !m_bPreviousUserPause) {
 		for(int32 i = 0; i < allChannels; i++) SampleManager.StopChannel(i);
 
@@ -8259,13 +9600,15 @@ cAudioManager::ServiceSoundEffects()
 	ProcessMissionAudio();
 	AdjustSamplesVolume();
 	ProcessActiveQueues();
-	for(int32 i = 0; i < m_nScriptObjectEntityTotal; ++i) {
-		object = (cAudioScriptObject *)m_asAudioEntities[m_anScriptObjectEntityIndices[i]].m_pEntity;
+	for(int32 i = 0; i < m_sAudioScriptObjectManager.m_nScriptObjectEntityTotal; ++i) {
+		cAudioScriptObject *object =
+		    (cAudioScriptObject *)m_asAudioEntities[m_sAudioScriptObjectManager.m_anScriptObjectEntityIndices[i]]
+		        .m_pEntity;
 		delete object;
-		m_asAudioEntities[m_anScriptObjectEntityIndices[i]].m_pEntity = nil;
-		DestroyEntity(m_anScriptObjectEntityIndices[i]);
+		m_asAudioEntities[m_sAudioScriptObjectManager.m_anScriptObjectEntityIndices[i]].m_pEntity = nil;
+		DestroyEntity(m_sAudioScriptObjectManager.m_anScriptObjectEntityIndices[i]);
 	}
-	m_nScriptObjectEntityTotal = 0;
+	m_sAudioScriptObjectManager.m_nScriptObjectEntityTotal = 0;
 }
 
 int8
@@ -8309,7 +9652,8 @@ cAudioManager::SetEffectsMasterVolume(uint8 volume) const
 void
 cAudioManager::SetEntityStatus(int32 id, uint8 status)
 {
-	if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots && m_asAudioEntities[id].m_bIsUsed) {
+	if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots &&
+	   m_asAudioEntities[id].m_bIsUsed) {
 		m_asAudioEntities[id].m_bStatus = status;
 	}
 }
@@ -8318,7 +9662,7 @@ void
 cAudioManager::SetMissionAudioLocation(float x, float y, float z)
 {
 	if(m_bIsInitialised) {
-		m_sMissionAudio.field_12 = 0;
+		m_sMissionAudio.m_bPredefinedProperties = 0;
 		m_sMissionAudio.m_vecPos = {x, y, z};
 	}
 }
@@ -8349,20 +9693,22 @@ cAudioManager::SetupJumboEngineSound(uint8 vol, int32 freq)
 	uint8 emittingVol = vol - gJumboVolOffsetPercentage / 100;
 	m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 180.f, m_sQueueSample.m_fDistance);
 	if(m_sQueueSample.m_bVolume) {
-		m_sQueueSample.m_counter = 3;
+		m_sQueueSample.m_nCounter = 3;
 		m_sQueueSample.m_nSampleIndex = SFX_JUMBO_ENGINE;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = false;
-		m_sQueueSample.field_16 = 1;
+		m_sQueueSample.m_bIs2D = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 1;
 		m_sQueueSample.m_nFrequency = freq;
 		m_sQueueSample.m_nLoopCount = 0;
 		m_sQueueSample.m_bEmittingVolume = emittingVol;
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_48 = 4.0f;
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 		m_sQueueSample.m_fSoundIntensity = 180.0f;
-		m_sQueueSample.field_56 = 0;
-		m_sQueueSample.field_76 = 4;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
+		m_sQueueSample.m_nReleasingVolumeDivider = 4;
 		m_sQueueSample.m_bReverbFlag = true;
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
@@ -8379,20 +9725,23 @@ cAudioManager::SetupJumboFlySound(uint8 emittingVol)
 	m_sQueueSample.m_bVolume = vol;
 	if(m_sQueueSample.m_bVolume) {
 		m_sQueueSample.m_nSampleIndex = SFX_JUMBO_DIST_FLY;
-		m_sQueueSample.m_counter = 0;
+		m_sQueueSample.m_nCounter = 0;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = false;
-		m_sQueueSample.field_16 = 1;
+		m_sQueueSample.m_bIs2D = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 1;
 		m_sQueueSample.m_bEmittingVolume = emittingVol;
 		m_sQueueSample.m_nLoopCount = 0;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_JUMBO_DIST_FLY);
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_JUMBO_DIST_FLY);
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
 		m_sQueueSample.m_fSoundIntensity = 440.0f;
-		m_sQueueSample.field_56 = 0;
-		m_sQueueSample.field_48 = 4.0f;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
+		m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 		m_sQueueSample.m_bReverbFlag = true;
-		m_sQueueSample.field_76 = 5;
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nReleasingVolumeDivider = 5;
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
 		AddSampleToRequestedQueue();
 	}
 	return true;
@@ -8406,25 +9755,28 @@ cAudioManager::SetupJumboRumbleSound(uint8 emittingVol)
 	m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 240.f, m_sQueueSample.m_fDistance);
 
 	if(m_sQueueSample.m_bVolume) {
-		m_sQueueSample.m_counter = 5;
+		m_sQueueSample.m_nCounter = 5;
 		m_sQueueSample.m_nSampleIndex = SFX_JUMBO_RUMBLE;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = true;
-		m_sQueueSample.field_16 = 1;
-		m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_JUMBO_RUMBLE);
+		m_sQueueSample.m_bIs2D = true;
+		m_sQueueSample.m_nReleasingVolumeModificator = 1;
+		m_sQueueSample.m_nFrequency =
+		    SampleManager.GetSampleBaseFrequency(SFX_JUMBO_RUMBLE);
 		m_sQueueSample.m_nLoopCount = 0;
 		m_sQueueSample.m_bEmittingVolume = emittingVol;
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_48 = 4.0f;
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 		m_sQueueSample.m_fSoundIntensity = 240.0f;
-		m_sQueueSample.field_56 = 0;
-		m_sQueueSample.field_76 = 12;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
+		m_sQueueSample.m_nReleasingVolumeDivider = 12;
 		m_sQueueSample.m_bOffset = 0;
 		m_sQueueSample.m_bReverbFlag = true;
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
-		m_sQueueSample.m_counter = 6;
+		m_sQueueSample.m_nCounter = 6;
 		m_sQueueSample.m_nSampleIndex = SFX_JUMBO_RUMBLE;
 		m_sQueueSample.m_nFrequency += 200;
 		m_sQueueSample.m_bOffset = maxVolume;
@@ -8440,24 +9792,27 @@ cAudioManager::SetupJumboTaxiSound(uint8 vol)
 
 	uint8 emittingVol = (vol >> 1) + ((vol >> 1) * m_sQueueSample.m_fDistance / 180);
 
-	if(m_sQueueSample.m_fDistance / 180 < 0.7f) emittingVol -= emittingVol * gJumboVolOffsetPercentage / 100;
+	if(m_sQueueSample.m_fDistance / 180 < 0.7f)
+		emittingVol -= emittingVol * gJumboVolOffsetPercentage / 100;
 	m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 180.f, m_sQueueSample.m_fDistance);
 
 	if(m_sQueueSample.m_bVolume) {
-		m_sQueueSample.m_counter = 1;
+		m_sQueueSample.m_nCounter = 1;
 		m_sQueueSample.m_nSampleIndex = SFX_JUMBO_TAXI;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = false;
-		m_sQueueSample.field_16 = 1;
+		m_sQueueSample.m_bIs2D = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 1;
 		m_sQueueSample.m_nFrequency = GetJumboTaxiFreq();
 		m_sQueueSample.m_nLoopCount = 0;
 		m_sQueueSample.m_bEmittingVolume = emittingVol;
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_48 = 4.0f;
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 		m_sQueueSample.m_fSoundIntensity = 180.0f;
-		m_sQueueSample.field_56 = 0;
-		m_sQueueSample.field_76 = 4;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
+		m_sQueueSample.m_nReleasingVolumeDivider = 4;
 		m_sQueueSample.m_bReverbFlag = true;
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
@@ -8473,20 +9828,22 @@ cAudioManager::SetupJumboWhineSound(uint8 emittingVol, int32 freq)
 	m_sQueueSample.m_bVolume = ComputeVolume(emittingVol, 170.f, m_sQueueSample.m_fDistance);
 
 	if(m_sQueueSample.m_bVolume) {
-		m_sQueueSample.m_counter = 2;
+		m_sQueueSample.m_nCounter = 2;
 		m_sQueueSample.m_nSampleIndex = SFX_JUMBO_WHINE;
 		m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-		m_sQueueSample.m_bIsDistant = false;
-		m_sQueueSample.field_16 = 1;
+		m_sQueueSample.m_bIs2D = false;
+		m_sQueueSample.m_nReleasingVolumeModificator = 1;
 		m_sQueueSample.m_nFrequency = freq;
 		m_sQueueSample.m_nLoopCount = 0;
 		m_sQueueSample.m_bEmittingVolume = emittingVol;
-		m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
-		m_sQueueSample.field_48 = 4.0f;
+		m_sQueueSample.m_nLoopStart =
+		    SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_nLoopEnd =
+		    SampleManager.GetSampleLoopEndOffset(m_sQueueSample.m_nSampleIndex);
+		m_sQueueSample.m_fSpeedMultiplier = 4.0f;
 		m_sQueueSample.m_fSoundIntensity = 170.0f;
-		m_sQueueSample.field_56 = 0;
-		m_sQueueSample.field_76 = 4;
+		m_sQueueSample.m_bReleasingSoundFlag = false;
+		m_sQueueSample.m_nReleasingVolumeDivider = 4;
 		m_sQueueSample.m_bReverbFlag = true;
 		m_sQueueSample.m_bRequireReflection = false;
 		AddSampleToRequestedQueue();
@@ -8524,19 +9881,19 @@ cAudioManager::SetupPedComments(cPedParams *params, uint32 sound)
 				case SOUND_AMMUNATION_WELCOME_3: emittingVol = maxVolume; break;
 				default:
 					if(CWorld::GetIsLineOfSightClear(TheCamera.GetPosition(),
-					                                 m_sQueueSample.m_vecPos, 1, 0, 0, 0, 0, 0,
-					                                 0)) {
+					                                 m_sQueueSample.m_vecPos, 1,
+					                                 0, 0, 0, 0, 0, 0)) {
 						emittingVol = maxVolume;
 					} else {
 						emittingVol = 31;
 					}
 					break;
 				}
-				m_sQueueSample.m_bVolume =
-				    ComputeVolume(emittingVol, soundIntensity, m_sQueueSample.m_fDistance);
-				pedComment.field_25 = 10;
+				m_sQueueSample.m_bVolume = ComputeVolume(
+				    emittingVol, soundIntensity, m_sQueueSample.m_fDistance);
+				pedComment.m_nProcess = 10;
 				if(m_sQueueSample.m_bVolume) {
-					pedComment.m_entityIndex = m_sQueueSample.m_nEntityIndex;
+					pedComment.m_nEntityIndex = m_sQueueSample.m_nEntityIndex;
 					pedComment.m_vecPos = m_sQueueSample.m_vecPos;
 					pedComment.m_fDistance = m_sQueueSample.m_fDistance;
 					pedComment.m_bVolume = m_sQueueSample.m_bVolume;
@@ -8548,26 +9905,30 @@ cAudioManager::SetupPedComments(cPedParams *params, uint32 sound)
 		switch(sound) {
 		case SOUND_PED_HELI_PLAYER_FOUND:
 			soundIntensity = 400.f;
-			pedComment.m_nSampleIndex = m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 29 +
-			                            SFX_POLICE_HELI_1;
+			pedComment.m_nSampleIndex =
+			    m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 29 +
+			    SFX_POLICE_HELI_1;
 			break;
 		case SOUND_PED_BODYCAST_HIT:
 			if(CTimer::GetTimeInMilliseconds() <= gNextCryTime) return;
 			soundIntensity = 50.f;
 			gNextCryTime = CTimer::GetTimeInMilliseconds() + 500;
 			pedComment.m_nSampleIndex =
-			    (m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] & 3) + SFX_PLASTER_BLOKE_1;
+			    (m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] & 3) +
+			    SFX_PLASTER_BLOKE_1;
 			break;
 		case SOUND_INJURED_PED_MALE_OUCH:
 		case SOUND_8A:
 			soundIntensity = 50.f;
-			pedComment.m_nSampleIndex = m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 15 +
-			                            SFX_GENERIC_MALE_GRUNT_1;
+			pedComment.m_nSampleIndex =
+			    m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 15 +
+			    SFX_GENERIC_MALE_GRUNT_1;
 			break;
 		case SOUND_INJURED_PED_FEMALE:
 			soundIntensity = 50.f;
-			pedComment.m_nSampleIndex = m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 11 +
-			                            SFX_GENERIC_FEMALE_GRUNT_1;
+			pedComment.m_nSampleIndex =
+			    m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % 11 +
+			    SFX_GENERIC_FEMALE_GRUNT_1;
 			break;
 		default: return;
 		}
@@ -8581,19 +9942,19 @@ cAudioManager::SetupPedComments(cPedParams *params, uint32 sound)
 				case SOUND_AMMUNATION_WELCOME_3: emittingVol = maxVolume; break;
 				default:
 					if(CWorld::GetIsLineOfSightClear(TheCamera.GetPosition(),
-					                                 m_sQueueSample.m_vecPos, 1, 0, 0, 0, 0, 0,
-					                                 0)) {
+					                                 m_sQueueSample.m_vecPos, 1,
+					                                 0, 0, 0, 0, 0, 0)) {
 						emittingVol = maxVolume;
 					} else {
 						emittingVol = 31;
 					}
 					break;
 				}
-				m_sQueueSample.m_bVolume =
-				    ComputeVolume(emittingVol, soundIntensity, m_sQueueSample.m_fDistance);
-				pedComment.field_25 = 10;
+				m_sQueueSample.m_bVolume = ComputeVolume(
+				    emittingVol, soundIntensity, m_sQueueSample.m_fDistance);
+				pedComment.m_nProcess = 10;
 				if(m_sQueueSample.m_bVolume) {
-					pedComment.m_entityIndex = m_sQueueSample.m_nEntityIndex;
+					pedComment.m_nEntityIndex = m_sQueueSample.m_nEntityIndex;
 					pedComment.m_vecPos = m_sQueueSample.m_vecPos;
 					pedComment.m_fDistance = m_sQueueSample.m_fDistance;
 					pedComment.m_bVolume = m_sQueueSample.m_bVolume;
@@ -8616,7 +9977,7 @@ cAudioManager::Terminate()
 		}
 
 		m_nAudioEntitiesTotal = 0;
-		m_nScriptObjectEntityTotal = 0;
+		m_sAudioScriptObjectManager.m_nScriptObjectEntityTotal = 0;
 		PreTerminateGameSpecificShutdown();
 
 		for(uint32 i = 0; i < DIGITALCHANNELS; i++) {
@@ -8625,7 +9986,7 @@ cAudioManager::Terminate()
 
 		SampleManager.Terminate();
 
-		m_bIsInitialised = 0;
+		m_bIsInitialised = false;
 		PostTerminateGameSpecificShutdown();
 	}
 }
@@ -8728,7 +10089,8 @@ cAudioManager::UpdateReflections()
 bool
 cAudioManager::UsesReverseWarning(int32 model) const
 {
-	return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH;
+	return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS ||
+	       model == COACH;
 }
 
 bool
@@ -8761,11 +10123,14 @@ void
 cAudioManager::AdjustSamplesVolume()
 {
 	for(int i = 0; i < m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; i++) {
-		tSound* pSample = &m_asSamples[m_bActiveSampleQueue][m_abSampleQueueIndexTable[m_bActiveSampleQueue][i] + 1];
+		tSound *pSample =
+		    &m_asSamples[m_bActiveSampleQueue]
+		                [m_abSampleQueueIndexTable[m_bActiveSampleQueue][i] + 1];
 
-		if(!pSample->m_bIsDistant)
-			pSample->m_bEmittingVolume = ComputeEmittingVolume(
-			    pSample->m_bEmittingVolume, pSample->m_fSoundIntensity, pSample->m_fDistance);
+		if(!pSample->m_bIs2D)
+			pSample->m_bEmittingVolume =
+			    ComputeEmittingVolume(pSample->m_bEmittingVolume,
+			                          pSample->m_fSoundIntensity, pSample->m_fDistance);
 	}
 }
 
@@ -8775,220 +10140,221 @@ cAudioManager::ComputeEmittingVolume(uint8 emittingVolume, float intensity, floa
 	float quatIntensity = intensity / 4.0f;
 	float diffIntensity = intensity - quatIntensity;
 	if(dist > diffIntensity)
-		return (quatIntensity - (dist - diffIntensity)) * (float)emittingVolume / quatIntensity;
+		return (quatIntensity - (dist - diffIntensity)) * (float)emittingVolume /
+		       quatIntensity;
 	return emittingVolume;
 }
 
-STARTPATCHES
-InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP);
-InjectHook(0x56AD30, &cAudioManager::AddPlayerCarSample, PATCH_JUMP);
-InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP);
-InjectHook(0x57B8D0, &cAudioManager::AddReleasingSounds, PATCH_JUMP);
-InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP);
-InjectHook(0x5697A0, &cAudioManager::CalculateDistance, PATCH_JUMP);
-InjectHook(0x57AA10, &cAudioManager::CheckForAnAudioFileOnCD, PATCH_JUMP);
-InjectHook(0x57C160, &cAudioManager::ClearActiveSamples, PATCH_JUMP);
-InjectHook(0x5796A0, &cAudioManager::ClearMissionAudio, PATCH_JUMP);
-InjectHook(0x57C120, &cAudioManager::ClearRequestedQueue, PATCH_JUMP);
-InjectHook(0x57AE00, &cAudioManager::ComputeDopplerEffectedFrequency, PATCH_JUMP);
-InjectHook(0x57AD20, &cAudioManager::ComputePan, PATCH_JUMP);
-InjectHook(0x57ABB0, &cAudioManager::ComputeVolume, PATCH_JUMP);
-InjectHook(0x57A310, &cAudioManager::CreateEntity, PATCH_JUMP);
-InjectHook(0x57A830, &cAudioManager::DestroyAllGameCreatedEntities, PATCH_JUMP);
-InjectHook(0x57A400, &cAudioManager::DestroyEntity, PATCH_JUMP);
-InjectHook(0x57C290, &cAudioManager::GenerateIntegerRandomNumberTable, PATCH_JUMP);
-InjectHook(0x57A8C0, &cAudioManager::Get3DProviderName, PATCH_JUMP);
-InjectHook(0x571110, &cAudioManager::GetArmyTalkSfx, PATCH_JUMP);
-InjectHook(0x573AB0, &cAudioManager::GetBlackBusinessFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x572050, &cAudioManager::GetBlackCasualFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x574380, &cAudioManager::GetBlackConstructionWorkerTalkSfx, PATCH_JUMP);
-InjectHook(0x571D80, &cAudioManager::GetBlackCriminalTalkSfx, PATCH_JUMP);
-InjectHook(0x5735E0, &cAudioManager::GetBlackDockerMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5724D0, &cAudioManager::GetBlackFatFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5726C0, &cAudioManager::GetBlackFatMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5728B0, &cAudioManager::GetBlackFemaleProstituteTalkSfx, PATCH_JUMP);
-InjectHook(0x572C20, &cAudioManager::GetBlackProjectFemaleOldTalkSfx, PATCH_JUMP);
-InjectHook(0x572D20, &cAudioManager::GetBlackProjectFemaleYoungTalkSfx, PATCH_JUMP);
-InjectHook(0x572AF0, &cAudioManager::GetBlackProjectMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5739C0, &cAudioManager::GetBlackWorkerMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x574FF0, &cAudioManager::GetBomberTalkSfx, PATCH_JUMP);
-InjectHook(0x5712C0, &cAudioManager::GetBusinessMaleOldTalkSfx, PATCH_JUMP);
-InjectHook(0x5713E0, &cAudioManager::GetBusinessMaleYoungTalkSfx, PATCH_JUMP);
-InjectHook(0x572040, &cAudioManager::GetCasualMaleOldTalkSfx, PATCH_JUMP);
-InjectHook(0x574FE0, &cAudioManager::GetCatatalinaTalkSfx, PATCH_JUMP);
-InjectHook(0x57AA30, &cAudioManager::GetCDAudioDriveLetter, PATCH_JUMP);
-InjectHook(0x573010, &cAudioManager::GetChinatownFemaleOldTalkSfx, PATCH_JUMP);
-InjectHook(0x5730F0, &cAudioManager::GetChinatownFemaleYoungTalkSfx, PATCH_JUMP);
-InjectHook(0x572E10, &cAudioManager::GetChinatownMaleOldTalkSfx, PATCH_JUMP);
-InjectHook(0x572F10, &cAudioManager::GetChinatownMaleYoungTalkSfx, PATCH_JUMP);
-InjectHook(0x575120, &cAudioManager::GetChunkyTalkSfx, PATCH_JUMP);
-InjectHook(0x571B00, &cAudioManager::GetColumbianTalkSfx, PATCH_JUMP);
-InjectHook(0x570EA0, &cAudioManager::GetCopTalkSfx, PATCH_JUMP);
-InjectHook(0x57A8F0, &cAudioManager::GetCurrent3DProviderIndex, PATCH_JUMP);
-InjectHook(0x571770, &cAudioManager::GetDiabloTalkSfx, PATCH_JUMP);
-InjectHook(0x569750, &cAudioManager::GetDistanceSquared, PATCH_JUMP);
-InjectHook(0x574DA0, &cAudioManager::GetEightTalkSfx, PATCH_JUMP);
-InjectHook(0x574040, &cAudioManager::GetFanFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x573F60, &cAudioManager::GetFanMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x571040, &cAudioManager::GetFBITalkSfx, PATCH_JUMP);
-InjectHook(0x572280, &cAudioManager::GetFemaleNo3TalkSfx, PATCH_JUMP);
-InjectHook(0x5712B0, &cAudioManager::GetFiremanTalkSfx, PATCH_JUMP);
-InjectHook(0x574E50, &cAudioManager::GetFrankieTalkSfx, PATCH_JUMP);
-InjectHook(0x575510, &cAudioManager::GetGenericFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x575460, &cAudioManager::GetGenericMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x571C30, &cAudioManager::GetHoodTalkSfx, PATCH_JUMP);
-InjectHook(0x5741F0, &cAudioManager::GetHospitalFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x574120, &cAudioManager::GetHospitalMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x56F410, &cAudioManager::GetJumboTaxiFreq, PATCH_JUMP);
-InjectHook(0x573310, &cAudioManager::GetLittleItalyFemaleOldTalkSfx, PATCH_JUMP);
-InjectHook(0x573400, &cAudioManager::GetLittleItalyFemaleYoungTalkSfx, PATCH_JUMP);
-InjectHook(0x5731E0, &cAudioManager::GetLittleItalyMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x571510, &cAudioManager::GetMafiaTalkSfx, PATCH_JUMP);
-InjectHook(0x571F40, &cAudioManager::GetMaleNo2TalkSfx, PATCH_JUMP);
-InjectHook(0x5711C0, &cAudioManager::GetMedicTalkSfx, PATCH_JUMP);
-InjectHook(0x5795D0, &cAudioManager::GetMissionAudioLoadingStatus, PATCH_JUMP);
-InjectHook(0x574F00, &cAudioManager::GetMistyTalkSfx, PATCH_JUMP);
-InjectHook(0x575340, &cAudioManager::GetNormalMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x57A8A0, &cAudioManager::GetNum3DProvidersAvailable, PATCH_JUMP);
-InjectHook(0x574FD0, &cAudioManager::GetOJGTalkSfx, PATCH_JUMP);
-InjectHook(0x570960, &cAudioManager::GetPedCommentSfx, PATCH_JUMP);
-InjectHook(0x570DB0, &cAudioManager::GetPhrase, PATCH_JUMP);
-InjectHook(0x56BF80, &cAudioManager::GetVehicleDriveWheelSkidValue, PATCH_JUMP);
-InjectHook(0x56C120, &cAudioManager::GetVehicleNonDriveWheelSkidValue, PATCH_JUMP);
-InjectHook(0x575240, &cAudioManager::GetPimpTalkSfx, PATCH_JUMP);
-InjectHook(0x570E00, &cAudioManager::GetPlayerTalkSfx, PATCH_JUMP);
-InjectHook(0x5737E0, &cAudioManager::GetScumFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5736D0, &cAudioManager::GetScumMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x575060, &cAudioManager::GetSecurityGuardTalkSfx, PATCH_JUMP);
-InjectHook(0x574480, &cAudioManager::GetShopperFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x574790, &cAudioManager::GetSpecialCharacterTalkSfx, PATCH_JUMP);
-InjectHook(0x573E90, &cAudioManager::GetStewardFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x573DC0, &cAudioManager::GetStewardMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x574690, &cAudioManager::GetStudentFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x574590, &cAudioManager::GetStudentMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x573CD0, &cAudioManager::GetSupermodelFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x573BD0, &cAudioManager::GetSupermodelMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x570F80, &cAudioManager::GetSwatTalkSfx, PATCH_JUMP);
-InjectHook(0x575190, &cAudioManager::GetTaxiDriverTalkSfx, PATCH_JUMP);
-InjectHook(0x571650, &cAudioManager::GetTriadTalkSfx, PATCH_JUMP);
-InjectHook(0x5723A0, &cAudioManager::GetWhiteBusinessFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x572170, &cAudioManager::GetWhiteCasualFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x574290, &cAudioManager::GetWhiteConstructionWorkerTalkSfx, PATCH_JUMP);
-InjectHook(0x571E60, &cAudioManager::GetWhiteCriminalTalkSfx, PATCH_JUMP);
-InjectHook(0x5734F0, &cAudioManager::GetWhiteDockerMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5727B0, &cAudioManager::GetWhiteFatFemaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5725D0, &cAudioManager::GetWhiteFatMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5729D0, &cAudioManager::GetWhiteFemaleProstituteTalkSfx, PATCH_JUMP);
-InjectHook(0x5738D0, &cAudioManager::GetWhiteWorkerMaleTalkSfx, PATCH_JUMP);
-InjectHook(0x5718D0, &cAudioManager::GetYakuzaTalkSfx, PATCH_JUMP);
-InjectHook(0x5719E0, &cAudioManager::GetYardieTalkSfx, PATCH_JUMP);
-InjectHook(0x56CAB0, &cAudioManager::HasAirBrakes, PATCH_JUMP);
-InjectHook(0x57A0E0, &cAudioManager::Initialise, PATCH_JUMP);
-InjectHook(0x57B030, &cAudioManager::InterrogateAudioEntities, PATCH_JUMP);
-InjectHook(0x57AA50, &cAudioManager::IsAudioInitialised, PATCH_JUMP);
-InjectHook(0x579650, &cAudioManager::IsMissionAudioSampleFinished, PATCH_JUMP);
-InjectHook(0x57A9C0, &cAudioManager::IsMP3RadioChannelAvailable, PATCH_JUMP);
-InjectHook(0x579520, &cAudioManager::MissionScriptAudioUsesPoliceChannel, PATCH_JUMP);
-InjectHook(0x56AD10, &cAudioManager::PlayerJustGotInCar, PATCH_JUMP);
-InjectHook(0x56AD20, &cAudioManager::PlayerJustLeftCar, PATCH_JUMP);
-InjectHook(0x579620, &cAudioManager::PlayLoadedMissionAudio, PATCH_JUMP);
-InjectHook(0x57A500, &cAudioManager::PlayOneShot, PATCH_JUMP);
-InjectHook(0x569420, &cAudioManager::PostInitialiseGameSpecificSetup, PATCH_JUMP);
-InjectHook(0x569640, &cAudioManager::PostTerminateGameSpecificShutdown, PATCH_JUMP);
-InjectHook(0x569400, &cAudioManager::PreInitialiseGameSpecificSetup, PATCH_JUMP);
-InjectHook(0x579550, &cAudioManager::PreloadMissionAudio, PATCH_JUMP);
-InjectHook(0x569570, &cAudioManager::PreTerminateGameSpecificShutdown, PATCH_JUMP);
+// STARTPATCHES
+// InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP);
+// InjectHook(0x56AD30, &cAudioManager::AddPlayerCarSample, PATCH_JUMP);
+// InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP);
+// InjectHook(0x57B8D0, &cAudioManager::AddReleasingSounds, PATCH_JUMP);
+// InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP);
+// InjectHook(0x5697A0, &cAudioManager::CalculateDistance, PATCH_JUMP);
+// InjectHook(0x57AA10, &cAudioManager::CheckForAnAudioFileOnCD, PATCH_JUMP);
+// InjectHook(0x57C160, &cAudioManager::ClearActiveSamples, PATCH_JUMP);
+// InjectHook(0x5796A0, &cAudioManager::ClearMissionAudio, PATCH_JUMP);
+// InjectHook(0x57C120, &cAudioManager::ClearRequestedQueue, PATCH_JUMP);
+// InjectHook(0x57AE00, &cAudioManager::ComputeDopplerEffectedFrequency, PATCH_JUMP);
+// InjectHook(0x57AD20, &cAudioManager::ComputePan, PATCH_JUMP);
+// InjectHook(0x57ABB0, &cAudioManager::ComputeVolume, PATCH_JUMP);
+// InjectHook(0x57A310, &cAudioManager::CreateEntity, PATCH_JUMP);
+// InjectHook(0x57A830, &cAudioManager::DestroyAllGameCreatedEntities, PATCH_JUMP);
+// InjectHook(0x57A400, &cAudioManager::DestroyEntity, PATCH_JUMP);
+// InjectHook(0x57C290, &cAudioManager::GenerateIntegerRandomNumberTable, PATCH_JUMP);
+// InjectHook(0x57A8C0, &cAudioManager::Get3DProviderName, PATCH_JUMP);
+// InjectHook(0x571110, &cAudioManager::GetArmyTalkSfx, PATCH_JUMP);
+// InjectHook(0x573AB0, &cAudioManager::GetBlackBusinessFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x572050, &cAudioManager::GetBlackCasualFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x574380, &cAudioManager::GetBlackConstructionWorkerTalkSfx, PATCH_JUMP);
+// InjectHook(0x571D80, &cAudioManager::GetBlackCriminalTalkSfx, PATCH_JUMP);
+// InjectHook(0x5735E0, &cAudioManager::GetBlackDockerMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5724D0, &cAudioManager::GetBlackFatFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5726C0, &cAudioManager::GetBlackFatMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5728B0, &cAudioManager::GetBlackFemaleProstituteTalkSfx, PATCH_JUMP);
+// InjectHook(0x572C20, &cAudioManager::GetBlackProjectFemaleOldTalkSfx, PATCH_JUMP);
+// InjectHook(0x572D20, &cAudioManager::GetBlackProjectFemaleYoungTalkSfx, PATCH_JUMP);
+// InjectHook(0x572AF0, &cAudioManager::GetBlackProjectMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5739C0, &cAudioManager::GetBlackWorkerMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x574FF0, &cAudioManager::GetBomberTalkSfx, PATCH_JUMP);
+// InjectHook(0x5712C0, &cAudioManager::GetBusinessMaleOldTalkSfx, PATCH_JUMP);
+// InjectHook(0x5713E0, &cAudioManager::GetBusinessMaleYoungTalkSfx, PATCH_JUMP);
+// InjectHook(0x572040, &cAudioManager::GetCasualMaleOldTalkSfx, PATCH_JUMP);
+// InjectHook(0x574FE0, &cAudioManager::GetCatatalinaTalkSfx, PATCH_JUMP);
+// InjectHook(0x57AA30, &cAudioManager::GetCDAudioDriveLetter, PATCH_JUMP);
+// InjectHook(0x573010, &cAudioManager::GetChinatownFemaleOldTalkSfx, PATCH_JUMP);
+// InjectHook(0x5730F0, &cAudioManager::GetChinatownFemaleYoungTalkSfx, PATCH_JUMP);
+// InjectHook(0x572E10, &cAudioManager::GetChinatownMaleOldTalkSfx, PATCH_JUMP);
+// InjectHook(0x572F10, &cAudioManager::GetChinatownMaleYoungTalkSfx, PATCH_JUMP);
+// InjectHook(0x575120, &cAudioManager::GetChunkyTalkSfx, PATCH_JUMP);
+// InjectHook(0x571B00, &cAudioManager::GetColumbianTalkSfx, PATCH_JUMP);
+// InjectHook(0x570EA0, &cAudioManager::GetCopTalkSfx, PATCH_JUMP);
+// InjectHook(0x57A8F0, &cAudioManager::GetCurrent3DProviderIndex, PATCH_JUMP);
+// InjectHook(0x571770, &cAudioManager::GetDiabloTalkSfx, PATCH_JUMP);
+// InjectHook(0x569750, &cAudioManager::GetDistanceSquared, PATCH_JUMP);
+// InjectHook(0x574DA0, &cAudioManager::GetEightTalkSfx, PATCH_JUMP);
+// InjectHook(0x574040, &cAudioManager::GetFanFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x573F60, &cAudioManager::GetFanMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x571040, &cAudioManager::GetFBITalkSfx, PATCH_JUMP);
+// InjectHook(0x572280, &cAudioManager::GetFemaleNo3TalkSfx, PATCH_JUMP);
+// InjectHook(0x5712B0, &cAudioManager::GetFiremanTalkSfx, PATCH_JUMP);
+// InjectHook(0x574E50, &cAudioManager::GetFrankieTalkSfx, PATCH_JUMP);
+// InjectHook(0x575510, &cAudioManager::GetGenericFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x575460, &cAudioManager::GetGenericMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x571C30, &cAudioManager::GetHoodTalkSfx, PATCH_JUMP);
+// InjectHook(0x5741F0, &cAudioManager::GetHospitalFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x574120, &cAudioManager::GetHospitalMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x56F410, &cAudioManager::GetJumboTaxiFreq, PATCH_JUMP);
+// InjectHook(0x573310, &cAudioManager::GetLittleItalyFemaleOldTalkSfx, PATCH_JUMP);
+// InjectHook(0x573400, &cAudioManager::GetLittleItalyFemaleYoungTalkSfx, PATCH_JUMP);
+// InjectHook(0x5731E0, &cAudioManager::GetLittleItalyMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x571510, &cAudioManager::GetMafiaTalkSfx, PATCH_JUMP);
+// InjectHook(0x571F40, &cAudioManager::GetMaleNo2TalkSfx, PATCH_JUMP);
+// InjectHook(0x5711C0, &cAudioManager::GetMedicTalkSfx, PATCH_JUMP);
+// InjectHook(0x5795D0, &cAudioManager::GetMissionAudioLoadingStatus, PATCH_JUMP);
+// InjectHook(0x574F00, &cAudioManager::GetMistyTalkSfx, PATCH_JUMP);
+// InjectHook(0x575340, &cAudioManager::GetNormalMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x57A8A0, &cAudioManager::GetNum3DProvidersAvailable, PATCH_JUMP);
+// InjectHook(0x574FD0, &cAudioManager::GetOJGTalkSfx, PATCH_JUMP);
+// InjectHook(0x570960, &cAudioManager::GetPedCommentSfx, PATCH_JUMP);
+// InjectHook(0x570DB0, &cAudioManager::GetPhrase, PATCH_JUMP);
+// InjectHook(0x56BF80, &cAudioManager::GetVehicleDriveWheelSkidValue, PATCH_JUMP);
+// InjectHook(0x56C120, &cAudioManager::GetVehicleNonDriveWheelSkidValue, PATCH_JUMP);
+// InjectHook(0x575240, &cAudioManager::GetPimpTalkSfx, PATCH_JUMP);
+// InjectHook(0x570E00, &cAudioManager::GetPlayerTalkSfx, PATCH_JUMP);
+// InjectHook(0x5737E0, &cAudioManager::GetScumFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5736D0, &cAudioManager::GetScumMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x575060, &cAudioManager::GetSecurityGuardTalkSfx, PATCH_JUMP);
+// InjectHook(0x574480, &cAudioManager::GetShopperFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x574790, &cAudioManager::GetSpecialCharacterTalkSfx, PATCH_JUMP);
+// InjectHook(0x573E90, &cAudioManager::GetStewardFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x573DC0, &cAudioManager::GetStewardMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x574690, &cAudioManager::GetStudentFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x574590, &cAudioManager::GetStudentMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x573CD0, &cAudioManager::GetSupermodelFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x573BD0, &cAudioManager::GetSupermodelMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x570F80, &cAudioManager::GetSwatTalkSfx, PATCH_JUMP);
+// InjectHook(0x575190, &cAudioManager::GetTaxiDriverTalkSfx, PATCH_JUMP);
+// InjectHook(0x571650, &cAudioManager::GetTriadTalkSfx, PATCH_JUMP);
+// InjectHook(0x5723A0, &cAudioManager::GetWhiteBusinessFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x572170, &cAudioManager::GetWhiteCasualFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x574290, &cAudioManager::GetWhiteConstructionWorkerTalkSfx, PATCH_JUMP);
+// InjectHook(0x571E60, &cAudioManager::GetWhiteCriminalTalkSfx, PATCH_JUMP);
+// InjectHook(0x5734F0, &cAudioManager::GetWhiteDockerMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5727B0, &cAudioManager::GetWhiteFatFemaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5725D0, &cAudioManager::GetWhiteFatMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5729D0, &cAudioManager::GetWhiteFemaleProstituteTalkSfx, PATCH_JUMP);
+// InjectHook(0x5738D0, &cAudioManager::GetWhiteWorkerMaleTalkSfx, PATCH_JUMP);
+// InjectHook(0x5718D0, &cAudioManager::GetYakuzaTalkSfx, PATCH_JUMP);
+// InjectHook(0x5719E0, &cAudioManager::GetYardieTalkSfx, PATCH_JUMP);
+// InjectHook(0x56CAB0, &cAudioManager::HasAirBrakes, PATCH_JUMP);
+// InjectHook(0x57A0E0, &cAudioManager::Initialise, PATCH_JUMP);
+// InjectHook(0x57B030, &cAudioManager::InterrogateAudioEntities, PATCH_JUMP);
+// InjectHook(0x57AA50, &cAudioManager::IsAudioInitialised, PATCH_JUMP);
+// InjectHook(0x579650, &cAudioManager::IsMissionAudioSampleFinished, PATCH_JUMP);
+// InjectHook(0x57A9C0, &cAudioManager::IsMP3RadioChannelAvailable, PATCH_JUMP);
+// InjectHook(0x579520, &cAudioManager::MissionScriptAudioUsesPoliceChannel, PATCH_JUMP);
+// InjectHook(0x56AD10, &cAudioManager::PlayerJustGotInCar, PATCH_JUMP);
+// InjectHook(0x56AD20, &cAudioManager::PlayerJustLeftCar, PATCH_JUMP);
+// InjectHook(0x579620, &cAudioManager::PlayLoadedMissionAudio, PATCH_JUMP);
+// InjectHook(0x57A500, &cAudioManager::PlayOneShot, PATCH_JUMP);
+// InjectHook(0x569420, &cAudioManager::PostInitialiseGameSpecificSetup, PATCH_JUMP);
+// InjectHook(0x569640, &cAudioManager::PostTerminateGameSpecificShutdown, PATCH_JUMP);
+// InjectHook(0x569400, &cAudioManager::PreInitialiseGameSpecificSetup, PATCH_JUMP);
+// InjectHook(0x579550, &cAudioManager::PreloadMissionAudio, PATCH_JUMP);
+// InjectHook(0x569570, &cAudioManager::PreTerminateGameSpecificShutdown, PATCH_JUMP);
 // InjectHook(0x57BA60, &cAudioManager::ProcessActiveQueues, PATCH_JUMP);
-InjectHook(0x56C940, &cAudioManager::ProcessAirBrakes, PATCH_JUMP);
-InjectHook(0x577B30, &cAudioManager::ProcessAirportScriptObject, PATCH_JUMP);
-InjectHook(0x56DE80, &cAudioManager::ProcessBoatEngine, PATCH_JUMP);
-InjectHook(0x56E500, &cAudioManager::ProcessBoatMovingOverWater, PATCH_JUMP);
-InjectHook(0x5790D0, &cAudioManager::ProcessBridge, PATCH_JUMP);
-InjectHook(0x579250, &cAudioManager::ProcessBridgeMotor, PATCH_JUMP);
-InjectHook(0x579310, &cAudioManager::ProcessBridgeOneShots, PATCH_JUMP);
-InjectHook(0x579170, &cAudioManager::ProcessBridgeWarning, PATCH_JUMP);
-InjectHook(0x56CC20, &cAudioManager::ProcessCarBombTick, PATCH_JUMP);
-InjectHook(0x577CA0, &cAudioManager::ProcessCinemaScriptObject, PATCH_JUMP);
-InjectHook(0x577E50, &cAudioManager::ProcessDocksScriptObject, PATCH_JUMP);
-InjectHook(0x56CAF0, &cAudioManager::ProcessEngineDamage, PATCH_JUMP);
-InjectHook(0x569870, &cAudioManager::ProcessEntity, PATCH_JUMP);
-InjectHook(0x575AC0, &cAudioManager::ProcessExplosions, PATCH_JUMP);
-InjectHook(0x578FD0, &cAudioManager::ProcessFireHydrant, PATCH_JUMP);
-InjectHook(0x5785E0, &cAudioManager::ProcessFrontEnd, PATCH_JUMP);
-InjectHook(0x56E6A0, &cAudioManager::ProcessHelicopter, PATCH_JUMP);
-InjectHook(0x577FE0, &cAudioManager::ProcessHomeScriptObject, PATCH_JUMP);
-InjectHook(0x56E8F0, &cAudioManager::ProcessJumbo, PATCH_JUMP);
-InjectHook(0x56EA40, &cAudioManager::ProcessJumboAccel, PATCH_JUMP);
-InjectHook(0x56EE40, &cAudioManager::ProcessJumboDecel, PATCH_JUMP);
-InjectHook(0x56ECF0, &cAudioManager::ProcessJumboFlying, PATCH_JUMP);
-InjectHook(0x56ED10, &cAudioManager::ProcessJumboLanding, PATCH_JUMP);
-InjectHook(0x56EC00, &cAudioManager::ProcessJumboTakeOff, PATCH_JUMP);
-InjectHook(0x56EA10, &cAudioManager::ProcessJumboTaxi, PATCH_JUMP);
-InjectHook(0x5777E0, &cAudioManager::ProcessLaunderetteScriptObject, PATCH_JUMP);
-InjectHook(0x576770, &cAudioManager::ProcessLoopingScriptObject, PATCH_JUMP);
-InjectHook(0x5796E0, &cAudioManager::ProcessMissionAudio, PATCH_JUMP);
-InjectHook(0x56A050, &cAudioManager::ProcessModelCarEngine, PATCH_JUMP);
-InjectHook(0x5760C0, &cAudioManager::ProcessOneShotScriptObject, PATCH_JUMP);
-InjectHook(0x56F450, &cAudioManager::ProcessPed, PATCH_JUMP);
-InjectHook(0x56F4D0, &cAudioManager::ProcessPedHeadphones, PATCH_JUMP);
+// InjectHook(0x56C940, &cAudioManager::ProcessAirBrakes, PATCH_JUMP);
+// InjectHook(0x577B30, &cAudioManager::ProcessAirportScriptObject, PATCH_JUMP);
+// InjectHook(0x56DE80, &cAudioManager::ProcessBoatEngine, PATCH_JUMP);
+// InjectHook(0x56E500, &cAudioManager::ProcessBoatMovingOverWater, PATCH_JUMP);
+// InjectHook(0x5790D0, &cAudioManager::ProcessBridge, PATCH_JUMP);
+// InjectHook(0x579250, &cAudioManager::ProcessBridgeMotor, PATCH_JUMP);
+// InjectHook(0x579310, &cAudioManager::ProcessBridgeOneShots, PATCH_JUMP);
+// InjectHook(0x579170, &cAudioManager::ProcessBridgeWarning, PATCH_JUMP);
+// InjectHook(0x56CC20, &cAudioManager::ProcessCarBombTick, PATCH_JUMP);
+// InjectHook(0x577CA0, &cAudioManager::ProcessCinemaScriptObject, PATCH_JUMP);
+// InjectHook(0x577E50, &cAudioManager::ProcessDocksScriptObject, PATCH_JUMP);
+// InjectHook(0x56CAF0, &cAudioManager::ProcessEngineDamage, PATCH_JUMP);
+// InjectHook(0x569870, &cAudioManager::ProcessEntity, PATCH_JUMP);
+// InjectHook(0x575AC0, &cAudioManager::ProcessExplosions, PATCH_JUMP);
+// InjectHook(0x578FD0, &cAudioManager::ProcessFireHydrant, PATCH_JUMP);
+// InjectHook(0x5785E0, &cAudioManager::ProcessFrontEnd, PATCH_JUMP);
+// InjectHook(0x56E6A0, &cAudioManager::ProcessHelicopter, PATCH_JUMP);
+// InjectHook(0x577FE0, &cAudioManager::ProcessHomeScriptObject, PATCH_JUMP);
+// InjectHook(0x56E8F0, &cAudioManager::ProcessJumbo, PATCH_JUMP);
+// InjectHook(0x56EA40, &cAudioManager::ProcessJumboAccel, PATCH_JUMP);
+// InjectHook(0x56EE40, &cAudioManager::ProcessJumboDecel, PATCH_JUMP);
+// InjectHook(0x56ECF0, &cAudioManager::ProcessJumboFlying, PATCH_JUMP);
+// InjectHook(0x56ED10, &cAudioManager::ProcessJumboLanding, PATCH_JUMP);
+// InjectHook(0x56EC00, &cAudioManager::ProcessJumboTakeOff, PATCH_JUMP);
+// InjectHook(0x56EA10, &cAudioManager::ProcessJumboTaxi, PATCH_JUMP);
+// InjectHook(0x5777E0, &cAudioManager::ProcessLaunderetteScriptObject, PATCH_JUMP);
+// InjectHook(0x576770, &cAudioManager::ProcessLoopingScriptObject, PATCH_JUMP);
+// InjectHook(0x5796E0, &cAudioManager::ProcessMissionAudio, PATCH_JUMP);
+// InjectHook(0x56A050, &cAudioManager::ProcessModelCarEngine, PATCH_JUMP);
+// InjectHook(0x5760C0, &cAudioManager::ProcessOneShotScriptObject, PATCH_JUMP);
+// InjectHook(0x56F450, &cAudioManager::ProcessPed, PATCH_JUMP);
+// InjectHook(0x56F4D0, &cAudioManager::ProcessPedHeadphones, PATCH_JUMP);
 // InjectHook(0x56F650, &cAudioManager::ProcessPedOneShots, PATCH_JUMP);
-InjectHook(0x5699C0, &cAudioManager::ProcessPhysical, PATCH_JUMP);
-InjectHook(0x56E860, &cAudioManager::ProcessPlane, PATCH_JUMP);
-InjectHook(0x56B0D0, &cAudioManager::ProcessPlayersVehicleEngine, PATCH_JUMP);
-InjectHook(0x578190, &cAudioManager::ProcessPoliceCellBeatingScriptObject, PATCH_JUMP);
-InjectHook(0x577280, &cAudioManager::ProcessPornCinema, PATCH_JUMP);
-InjectHook(0x578A80, &cAudioManager::ProcessProjectiles, PATCH_JUMP);
-InjectHook(0x569CC0, &cAudioManager::ProcessRainOnVehicle, PATCH_JUMP);
-InjectHook(0x569700, &cAudioManager::ProcessReverb, PATCH_JUMP);
-InjectHook(0x569E50, &cAudioManager::ProcessReverseGear, PATCH_JUMP);
-InjectHook(0x577630, &cAudioManager::ProcessSawMillScriptObject, PATCH_JUMP);
-InjectHook(0x576070, &cAudioManager::ProcessScriptObject, PATCH_JUMP);
-InjectHook(0x577970, &cAudioManager::ProcessShopScriptObject, PATCH_JUMP);
-InjectHook(0x5697D0, &cAudioManager::ProcessSpecial, PATCH_JUMP);
-InjectHook(0x56DBF0, &cAudioManager::ProcessTrainNoise, PATCH_JUMP);
-InjectHook(0x569A00, &cAudioManager::ProcessVehicle, PATCH_JUMP);
-InjectHook(0x56C770, &cAudioManager::ProcessVehicleDoors, PATCH_JUMP);
-InjectHook(0x56C200, &cAudioManager::ProcessVehicleHorn, PATCH_JUMP);
-InjectHook(0x56C640, &cAudioManager::ProcessVehicleReverseWarning, PATCH_JUMP);
-InjectHook(0x56A230, &cAudioManager::ProcessVehicleRoadNoise, PATCH_JUMP);
-InjectHook(0x56C420, &cAudioManager::ProcessVehicleSirenOrAlarm, PATCH_JUMP);
-InjectHook(0x56BCB0, &cAudioManager::ProcessVehicleSkidding, PATCH_JUMP);
-InjectHook(0x575F30, &cAudioManager::ProcessWaterCannon, PATCH_JUMP);
-InjectHook(0x578370, &cAudioManager::ProcessWeather, PATCH_JUMP);
-InjectHook(0x56A440, &cAudioManager::ProcessWetRoadNoise, PATCH_JUMP);
-InjectHook(0x577530, &cAudioManager::ProcessWorkShopScriptObject, PATCH_JUMP);
-InjectHook(0x57AF90, &cAudioManager::RandomDisplacement, PATCH_JUMP);
-InjectHook(0x57A9F0, &cAudioManager::ReacquireDigitalHandle, PATCH_JUMP);
-InjectHook(0x57A9E0, &cAudioManager::ReleaseDigitalHandle, PATCH_JUMP);
-InjectHook(0x569650, &cAudioManager::ResetAudioLogicTimers, PATCH_JUMP);
-InjectHook(0x57A7B0, &cAudioManager::ResetTimers, PATCH_JUMP);
-InjectHook(0x57A2A0, &cAudioManager::Service, PATCH_JUMP);
-InjectHook(0x57AA60, &cAudioManager::ServiceSoundEffects, PATCH_JUMP);
-InjectHook(0x57A910, &cAudioManager::SetCurrent3DProvider, PATCH_JUMP);
-InjectHook(0x57AA00, &cAudioManager::SetDynamicAcousticModelingStatus, PATCH_JUMP);
-InjectHook(0x57A770, &cAudioManager::SetEffectsFadeVolume, PATCH_JUMP);
-InjectHook(0x57A730, &cAudioManager::SetEffectsMasterVolume, PATCH_JUMP);
-InjectHook(0x57A4C0, &cAudioManager::SetEntityStatus, PATCH_JUMP);
-InjectHook(0x5795F0, &cAudioManager::SetMissionAudioLocation, PATCH_JUMP);
-InjectHook(0x57A790, &cAudioManager::SetMusicFadeVolume, PATCH_JUMP);
-InjectHook(0x57A750, &cAudioManager::SetMusicMasterVolume, PATCH_JUMP);
-InjectHook(0x57A9A0, &cAudioManager::SetSpeakerConfig, PATCH_JUMP);
-InjectHook(0x56F230, &cAudioManager::SetupJumboFlySound, PATCH_JUMP);
-InjectHook(0x56F310, &cAudioManager::SetupJumboRumbleSound, PATCH_JUMP);
-InjectHook(0x56EF20, &cAudioManager::SetupJumboTaxiSound, PATCH_JUMP);
-InjectHook(0x56F070, &cAudioManager::SetupJumboWhineSound, PATCH_JUMP);
-InjectHook(0x570690, &cAudioManager::SetupPedComments, PATCH_JUMP);
-InjectHook(0x57A150, &cAudioManager::Terminate, PATCH_JUMP);
-InjectHook(0x57AC60, &cAudioManager::TranslateEntity, PATCH_JUMP);
-InjectHook(0x56AC80, &cAudioManager::UpdateGasPedalAudio, PATCH_JUMP);
-InjectHook(0x57B470, &cAudioManager::UpdateReflections, PATCH_JUMP);
-InjectHook(0x56C600, &cAudioManager::UsesReverseWarning, PATCH_JUMP);
-InjectHook(0x56C3C0, &cAudioManager::UsesSiren, PATCH_JUMP);
-InjectHook(0x56C3F0, &cAudioManager::UsesSirenSwitching, PATCH_JUMP);
+// InjectHook(0x5699C0, &cAudioManager::ProcessPhysical, PATCH_JUMP);
+// InjectHook(0x56E860, &cAudioManager::ProcessPlane, PATCH_JUMP);
+// InjectHook(0x56B0D0, &cAudioManager::ProcessPlayersVehicleEngine, PATCH_JUMP);
+// InjectHook(0x578190, &cAudioManager::ProcessPoliceCellBeatingScriptObject, PATCH_JUMP);
+// InjectHook(0x577280, &cAudioManager::ProcessPornCinema, PATCH_JUMP);
+// InjectHook(0x578A80, &cAudioManager::ProcessProjectiles, PATCH_JUMP);
+// InjectHook(0x569CC0, &cAudioManager::ProcessRainOnVehicle, PATCH_JUMP);
+// InjectHook(0x569700, &cAudioManager::ProcessReverb, PATCH_JUMP);
+// InjectHook(0x569E50, &cAudioManager::ProcessReverseGear, PATCH_JUMP);
+// InjectHook(0x577630, &cAudioManager::ProcessSawMillScriptObject, PATCH_JUMP);
+// InjectHook(0x576070, &cAudioManager::ProcessScriptObject, PATCH_JUMP);
+// InjectHook(0x577970, &cAudioManager::ProcessShopScriptObject, PATCH_JUMP);
+// InjectHook(0x5697D0, &cAudioManager::ProcessSpecial, PATCH_JUMP);
+// InjectHook(0x56DBF0, &cAudioManager::ProcessTrainNoise, PATCH_JUMP);
+// InjectHook(0x569A00, &cAudioManager::ProcessVehicle, PATCH_JUMP);
+// InjectHook(0x56C770, &cAudioManager::ProcessVehicleDoors, PATCH_JUMP);
+// InjectHook(0x56C200, &cAudioManager::ProcessVehicleHorn, PATCH_JUMP);
+// InjectHook(0x56C640, &cAudioManager::ProcessVehicleReverseWarning, PATCH_JUMP);
+// InjectHook(0x56A230, &cAudioManager::ProcessVehicleRoadNoise, PATCH_JUMP);
+// InjectHook(0x56C420, &cAudioManager::ProcessVehicleSirenOrAlarm, PATCH_JUMP);
+// InjectHook(0x56BCB0, &cAudioManager::ProcessVehicleSkidding, PATCH_JUMP);
+// InjectHook(0x575F30, &cAudioManager::ProcessWaterCannon, PATCH_JUMP);
+// InjectHook(0x578370, &cAudioManager::ProcessWeather, PATCH_JUMP);
+// InjectHook(0x56A440, &cAudioManager::ProcessWetRoadNoise, PATCH_JUMP);
+// InjectHook(0x577530, &cAudioManager::ProcessWorkShopScriptObject, PATCH_JUMP);
+// InjectHook(0x57AF90, &cAudioManager::RandomDisplacement, PATCH_JUMP);
+// InjectHook(0x57A9F0, &cAudioManager::ReacquireDigitalHandle, PATCH_JUMP);
+// InjectHook(0x57A9E0, &cAudioManager::ReleaseDigitalHandle, PATCH_JUMP);
+// InjectHook(0x569650, &cAudioManager::ResetAudioLogicTimers, PATCH_JUMP);
+// InjectHook(0x57A7B0, &cAudioManager::ResetTimers, PATCH_JUMP);
+// InjectHook(0x57A2A0, &cAudioManager::Service, PATCH_JUMP);
+// InjectHook(0x57AA60, &cAudioManager::ServiceSoundEffects, PATCH_JUMP);
+// InjectHook(0x57A910, &cAudioManager::SetCurrent3DProvider, PATCH_JUMP);
+// InjectHook(0x57AA00, &cAudioManager::SetDynamicAcousticModelingStatus, PATCH_JUMP);
+// InjectHook(0x57A770, &cAudioManager::SetEffectsFadeVolume, PATCH_JUMP);
+// InjectHook(0x57A730, &cAudioManager::SetEffectsMasterVolume, PATCH_JUMP);
+// InjectHook(0x57A4C0, &cAudioManager::SetEntityStatus, PATCH_JUMP);
+// InjectHook(0x5795F0, &cAudioManager::SetMissionAudioLocation, PATCH_JUMP);
+// InjectHook(0x57A790, &cAudioManager::SetMusicFadeVolume, PATCH_JUMP);
+// InjectHook(0x57A750, &cAudioManager::SetMusicMasterVolume, PATCH_JUMP);
+// InjectHook(0x57A9A0, &cAudioManager::SetSpeakerConfig, PATCH_JUMP);
+// InjectHook(0x56F230, &cAudioManager::SetupJumboFlySound, PATCH_JUMP);
+// InjectHook(0x56F310, &cAudioManager::SetupJumboRumbleSound, PATCH_JUMP);
+// InjectHook(0x56EF20, &cAudioManager::SetupJumboTaxiSound, PATCH_JUMP);
+// InjectHook(0x56F070, &cAudioManager::SetupJumboWhineSound, PATCH_JUMP);
+// InjectHook(0x570690, &cAudioManager::SetupPedComments, PATCH_JUMP);
+// InjectHook(0x57A150, &cAudioManager::Terminate, PATCH_JUMP);
+// InjectHook(0x57AC60, &cAudioManager::TranslateEntity, PATCH_JUMP);
+// InjectHook(0x56AC80, &cAudioManager::UpdateGasPedalAudio, PATCH_JUMP);
+// InjectHook(0x57B470, &cAudioManager::UpdateReflections, PATCH_JUMP);
+// InjectHook(0x56C600, &cAudioManager::UsesReverseWarning, PATCH_JUMP);
+// InjectHook(0x56C3C0, &cAudioManager::UsesSiren, PATCH_JUMP);
+// InjectHook(0x56C3F0, &cAudioManager::UsesSirenSwitching, PATCH_JUMP);
 
-InjectHook(0x57C2B0, &cAudioManager::AdjustSamplesVolume, PATCH_JUMP);
-InjectHook(0x57C320, &cAudioManager::ComputeEmittingVolume, PATCH_JUMP);
+// InjectHook(0x57C2B0, &cAudioManager::AdjustSamplesVolume, PATCH_JUMP);
+// InjectHook(0x57C320, &cAudioManager::ComputeEmittingVolume, PATCH_JUMP);
 
-InjectHook(0x5755C0, &cPedComments::Add, PATCH_JUMP);
-InjectHook(0x575730, &cPedComments::Process, PATCH_JUMP);
-ENDPATCHES
+// InjectHook(0x5755C0, &cPedComments::Add, PATCH_JUMP);
+// InjectHook(0x575730, &cPedComments::Process, PATCH_JUMP);
+// ENDPATCHES
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
index 0be1e38a..31a07f9b 100644
--- a/src/audio/AudioManager.h
+++ b/src/audio/AudioManager.h
@@ -1,13 +1,14 @@
-#pragma once
+#pragma once
 
-#include "DMAudio.h"
 #include "common.h"
 #include "config.h"
+
+#include "DMAudio.h"
+
 #include "AudioCollision.h"
 #include "PoliceRadio.h"
 
-enum eScriptSounds : int16
-{
+enum eScriptSounds : int16 {
 	SCRIPT_SOUND_0 = 0,
 	SCRIPT_SOUND_1 = 1,
 	SCRIPT_SOUND_2 = 2,
@@ -138,47 +139,47 @@ class tSound
 {
 public:
 	int32 m_nEntityIndex;
-	int32 m_counter;
+	int32 m_nCounter;
 	int32 m_nSampleIndex;
 	uint8 m_bBankIndex;
-	bool m_bIsDistant;
-	uint8 field_14;
-	uint8 field_15;
-	int32 field_16;
+	bool m_bIs2D;
+	uint8 field_14; // unused
+	uint8 field_15; // unused
+	int32 m_nReleasingVolumeModificator;
 	int32 m_nFrequency;
 	uint8 m_bVolume;
-	uint8 field_25;
-	uint8 field_26;
-	uint8 field_27;
+	uint8 field_25; // unused
+	uint8 field_26; // unused
+	uint8 field_27; // unused
 	float m_fDistance;
 	int32 m_nLoopCount;
 	int32 m_nLoopStart;
 	int32 m_nLoopEnd;
 	uint8 m_bEmittingVolume;
-	uint8 field_45;
-	uint8 field_46;
-	uint8 field_47;
-	float field_48;
+	uint8 field_45; // unused
+	uint8 field_46; // unused
+	uint8 field_47; // unused
+	float m_fSpeedMultiplier;
 	float m_fSoundIntensity;
-	uint8 field_56;
-	uint8 field_57;
-	uint8 field_58;
-	uint8 field_59;
+	bool m_bReleasingSoundFlag;
+	uint8 field_57; // unused
+	uint8 field_58; // unused
+	uint8 field_59; // unused
 	CVector m_vecPos;
 	bool m_bReverbFlag;
 	uint8 m_bLoopsRemaining;
-	bool m_bRequireReflection;
+	bool m_bRequireReflection; // Used for oneshots
 	uint8 m_bOffset;
-	int32 field_76;
-	uint8 m_bIsProcessed;
-	uint8 m_bLoopEnded;
-	uint8 field_82;
-	uint8 field_83;
-	int32 calculatedVolume;
-	int8 field_88;
-	uint8 field_89;
-	uint8 field_90;
-	uint8 field_91;
+	int32 m_nReleasingVolumeDivider;
+	bool m_bIsProcessed;
+	bool m_bLoopEnded;
+	uint8 field_82; // unused
+	uint8 field_83; // unused
+	int32 m_nCalculatedVolume;
+	int8 m_nVolumeChange;
+	uint8 field_89; // unused
+	uint8 field_90; // unused
+	uint8 field_91; // unused
 
 	// no methods
 };
@@ -196,7 +197,7 @@ public:
 	bool m_bIsUsed;
 	uint8 m_bStatus;
 	int16 m_awAudioEvent[NUM_AUDIOENTITY_EVENTS];
-	uint8 gap_18[2];
+	//uint8 gap_18[2];
 	float m_afVolume[NUM_AUDIOENTITY_EVENTS];
 	uint8 m_AudioEvents;
 	uint8 field_25[3];
@@ -210,12 +211,11 @@ class tPedComment
 {
 public:
 	int32 m_nSampleIndex;
-	int32 m_entityIndex;
+	int32 m_nEntityIndex;
 	CVector m_vecPos;
 	float m_fDistance;
 	uint8 m_bVolume;
-	int8 field_25; // allocated time?
-	uint8 gap_26[2];
+	int8 m_nProcess;
 
 	// no methods
 };
@@ -226,14 +226,13 @@ class cPedComments
 {
 public:
 	tPedComment m_asPedComments[NUM_PED_COMMENTS_BANKS][NUM_PED_COMMENTS_SLOTS];
-	uint8 indexMap[NUM_PED_COMMENTS_BANKS][NUM_PED_COMMENTS_SLOTS];
-	uint8 nrOfCommentsInBank[NUM_PED_COMMENTS_BANKS];
-	uint8 activeBank;
-	uint8 gap_1163[1];
+	uint8 m_nIndexMap[NUM_PED_COMMENTS_BANKS][NUM_PED_COMMENTS_SLOTS];
+	uint8 m_nCommentsInBank[NUM_PED_COMMENTS_BANKS];
+	uint8 m_nActiveBank;
 
-	// reversed all methods
-	void Add(tPedComment *com); /// ok
-	void Process();             /// ok
+	cPedComments();
+	void Add(tPedComment *com);
+	void Process();
 };
 
 static_assert(sizeof(cPedComments) == 1164, "cPedComments: error");
@@ -244,23 +243,35 @@ class cMissionAudio
 {
 public:
 	CVector m_vecPos;
-	uint8 field_12;
-	uint8 gap_13[3];
+	bool m_bPredefinedProperties;
+	//uint8 gap_13[3];
 	int m_nSampleIndex;
 	uint8 m_bLoadingStatus;
 	uint8 m_bPlayStatus;
-	uint8 field_22;
-	uint8 field_23;
-	int field_24;
+	uint8 field_22; // todo find a name
+	uint8 field_23; // unused
+	int32 m_nMissionAudioCounter;
 	bool m_bIsPlayed;
-	uint8 field_29;
-	uint8 field_30;
-	uint8 field_31;
-	// no methods
+	uint8 field_29; // unused
+	uint8 field_30; // unused
+	uint8 field_31; // unused
+	                // no methods
 };
 
 static_assert(sizeof(cMissionAudio) == 32, "cMissionAudio: error");
 
+// name made up
+class cAudioScriptObjectManager
+{
+public:
+	int32 m_anScriptObjectEntityIndices[NUM_SCRIPT_MAX_ENTITIES];
+	int32 m_nScriptObjectEntityTotal;
+
+	cAudioScriptObjectManager() { m_nScriptObjectEntityTotal = 0; }
+	~cAudioScriptObjectManager() { m_nScriptObjectEntityTotal = 0; }
+};
+
+
 class cVehicleParams;
 class CPlane;
 class CVehicle;
@@ -289,22 +300,22 @@ class cAudioManager
 {
 public:
 	bool m_bIsInitialised;
-	uint8 field_1;
-	uint8 field_2;
+	uint8 field_1; // unused
+	bool m_bFifthFrameFlag;
 	uint8 m_bActiveSamples;
-	uint8 field_4;
+	uint8 field_4; // unused
 	bool m_bDynamicAcousticModelingStatus;
-	uint8 field_6;
-	uint8 field_7;
-	float speedOfSound;
+	uint8 field_6; // unused
+	uint8 field_7; // unused
+	float m_fSpeedOfSound;
 	bool m_bTimerJustReset;
-	uint8 field_13;
-	uint8 field_14;
-	uint8 field_15;
+	uint8 field_13; // unused
+	uint8 field_14; // unused
+	uint8 field_15; // unused
 	int32 m_nTimer;
 	tSound m_sQueueSample;
 	bool m_bActiveSampleQueue;
-	uint8 gap_109[3];
+	uint8 gap_109[3]; // unused
 	tSound m_asSamples[NUM_SOUNDS_SAMPLES_BANKS][NUM_SOUNDS_SAMPLES_SLOTS];
 	uint8 m_abSampleQueueIndexTable[NUM_SOUNDS_SAMPLES_BANKS][NUM_SOUNDS_SAMPLES_SLOTS];
 	uint8 m_bSampleRequestQueuesStatus[NUM_SOUNDS_SAMPLES_BANKS];
@@ -314,8 +325,7 @@ public:
 	int32 m_nAudioEntitiesTotal;
 	CVector m_avecReflectionsPos[NUM_AUDIO_REFLECTIONS];
 	float m_afReflectionsDistances[NUM_AUDIO_REFLECTIONS];
-	int32 m_anScriptObjectEntityIndices[NUM_SCRIPT_MAX_ENTITIES];
-	int32 m_nScriptObjectEntityTotal;
+	cAudioScriptObjectManager m_sAudioScriptObjectManager;
 	cPedComments m_sPedComments;
 	int32 m_nFireAudioEntity;
 	int32 m_nWaterCannonEntity;
@@ -328,12 +338,15 @@ public:
 	int32 m_nBridgeEntity;
 	cMissionAudio m_sMissionAudio;
 	int32 m_anRandomTable[5];
-	uint8 field_19192;
+	uint8 m_bTimeSpent;
 	uint8 m_bUserPause;
 	uint8 m_bPreviousUserPause;
-	uint8 field_19195; // time?
+	uint8 field_19195; // unused
 	uint32 m_FrameCounter;
 
+	cAudioManager();
+	~cAudioManager();
+
 	// getters
 	uint32 GetFrameCounter() const { return m_FrameCounter; }
 	float GetReflectionsDistance(int32 idx) const { return m_afReflectionsDistances[idx]; }
@@ -341,29 +354,29 @@ public:
 	bool IsMissionAudioPlaying() const { return m_sMissionAudio.m_bPlayStatus == 1; }
 
 	// "Should" be in alphabetic order, except "getXTalkSfx"
-	void AddDetailsToRequestedOrderList(uint8 sample); /// ok (check once more)
+	void AddDetailsToRequestedOrderList(uint8 sample);
 	void AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sample, uint8 unk1,
-	                        uint8 counter, bool notLooping); /// ok
-	void AddReflectionsToRequestedQueue();                   /// ok (check value)
-	void AddReleasingSounds();                               /// ok (check)
-	void AddSampleToRequestedQueue();                        /// ok
-	void AgeCrimes();                                        /// ok
+	                        uint8 counter, bool notLooping);
+	void AddReflectionsToRequestedQueue();
+	void AddReleasingSounds();
+	void AddSampleToRequestedQueue();
+	void AgeCrimes();
 
-	void CalculateDistance(bool &condition, float dist); /// ok
-	bool CheckForAnAudioFileOnCD() const;                /// ok
-	void ClearActiveSamples();                           /// ok
-	void ClearMissionAudio();                            /// ok
-	void ClearRequestedQueue();                          /// ok
+	void CalculateDistance(bool &condition, float dist);
+	bool CheckForAnAudioFileOnCD() const;
+	void ClearActiveSamples();
+	void ClearMissionAudio();
+	void ClearRequestedQueue();
 	int32 ComputeDopplerEffectedFrequency(uint32 oldFreq, float position1, float position2,
-	                                      float speedMultiplier) const;                    /// ok
-	int32 ComputePan(float, CVector *);                                                    /// ok
-	uint8 ComputeVolume(uint8 emittingVolume, float soundIntensity, float distance) const; /// ok
-	int32 CreateEntity(int32 type, void *entity);                                          /// ok
+	                                      float speedMultiplier) const;
+	int32 ComputePan(float, CVector *);
+	uint8 ComputeVolume(uint8 emittingVolume, float soundIntensity, float distance) const;
+	int32 CreateEntity(int32 type, void *entity);
 
-	void DestroyAllGameCreatedEntities(); /// ok
-	void DestroyEntity(int32 id);         /// ok
-	void DoJumboVolOffset() const;        /// ok
-	void DoPoliceRadioCrackle();          /// ok
+	void DestroyAllGameCreatedEntities();
+	void DestroyEntity(int32 id);
+	void DoJumboVolOffset() const;
+	void DoPoliceRadioCrackle();
 
 	// functions returning talk sfx,
 	// order from GetPedCommentSfx
@@ -445,154 +458,151 @@ public:
 	uint32 GetGenericFemaleTalkSfx(int16 sound);
 	// end of functions returning talk sfx
 
-	void GenerateIntegerRandomNumberTable(); /// ok
+	void GenerateIntegerRandomNumberTable();
 	char *Get3DProviderName(uint8 id) const;
 	uint8 GetCDAudioDriveLetter() const;
-	int8 GetCurrent3DProviderIndex() const;                            /// ok
+	int8 GetCurrent3DProviderIndex() const;
 	float GetCollisionLoopingRatio(uint32 a, uint32 b, float c) const; // not used
-	float GetCollisionOneShotRatio(int32 a, float b) const;            /// ok
-	float GetCollisionRatio(float a, float b, float c, float d) const; /// ok
-	float GetDistanceSquared(CVector *v) const;                        /// ok
-	int32 GetJumboTaxiFreq() const;                                    /// ok
-	bool GetMissionAudioLoadingStatus() const;                         /// ok
-	int8 GetMissionScriptPoliceAudioPlayingStatus() const;             /// ok
+	float GetCollisionOneShotRatio(int32 a, float b) const;
+	float GetCollisionRatio(float a, float b, float c, float d) const;
+	float GetDistanceSquared(CVector *v) const;
+	int32 GetJumboTaxiFreq() const;
+	bool GetMissionAudioLoadingStatus() const;
+	int8 GetMissionScriptPoliceAudioPlayingStatus() const;
 	uint8 GetNum3DProvidersAvailable() const;
 	int32 GetPedCommentSfx(CPed *ped, int32 sound);
 	void GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint32 maxOffset) const;
 	float GetVehicleDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile,
-	                                    cTransmission *transmission,
-	                                    float velocityChange); /// ok
+	                                    cTransmission *transmission, float velocityChange);
 	float GetVehicleNonDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile,
-	                                       cTransmission *transmission,
-	                                       float velocityChange); /// ok
+	                                       cTransmission *transmission, float velocityChange);
 
-	bool HasAirBrakes(int32 model) const; /// ok
+	bool HasAirBrakes(int32 model) const;
 
-	void Initialise();                   /// ok
-	void InitialisePoliceRadio();        /// ok
-	void InitialisePoliceRadioZones();   /// ok
-	void InterrogateAudioEntities();     /// ok
-	bool IsAudioInitialised() const;     /// ok
-	bool IsMissionAudioSampleFinished(); /// ok
+	void Initialise();
+	void InitialisePoliceRadio();
+	void InitialisePoliceRadioZones();
+	void InterrogateAudioEntities();
+	bool IsAudioInitialised() const;
+	bool IsMissionAudioSampleFinished();
 	bool IsMP3RadioChannelAvailable() const;
 
-	bool MissionScriptAudioUsesPoliceChannel(int32 soundMission) const; /// ok
+	bool MissionScriptAudioUsesPoliceChannel(int32 soundMission) const;
 
-	void PlayLoadedMissionAudio();                         /// ok
-	void PlayOneShot(int32 index, int16 sound, float vol); /// ok
-	void PlaySuspectLastSeen(float x, float y, float z);   /// ok
-	void PlayerJustGotInCar() const;                       /// ok
-	void PlayerJustLeftCar() const;                        /// ok
-	void PostInitialiseGameSpecificSetup();                /// ok
-	void PostTerminateGameSpecificShutdown();              /// ok
-	void PreInitialiseGameSpecificSetup() const;           /// ok
-	void PreloadMissionAudio(const char *name);            /// ok
-	void PreTerminateGameSpecificShutdown();               /// ok
+	void PlayLoadedMissionAudio();
+	void PlayOneShot(int32 index, int16 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(const char *name);
+	void PreTerminateGameSpecificShutdown();
 	/// processX - main logic of adding new sounds
-	void ProcessActiveQueues();                              /// ok
-	bool ProcessAirBrakes(cVehicleParams *params);           /// ok
-	void ProcessAirportScriptObject(uint8 sound);            /// ok
-	bool ProcessBoatEngine(cVehicleParams *params);          /// ok
-	bool ProcessBoatMovingOverWater(cVehicleParams *params); /// ok
-	void ProcessBridge();                                    /// ok
-	void ProcessBridgeMotor();                               /// ok
-	void ProcessBridgeOneShots();                            /// ok
-	void ProcessBridgeWarning();                             /// ok
-	bool ProcessCarBombTick(cVehicleParams *params);         /// ok
-	void ProcessCesna(cVehicleParams *params);               /// ok
-	void ProcessCinemaScriptObject(uint8 sound);             /// ok
-	void ProcessCrane();                                     /// ok
-	void ProcessDocksScriptObject(uint8 sound);              /// ok
-	bool ProcessEngineDamage(cVehicleParams *params);        /// ok
-	void ProcessEntity(int32 sound);                         /// ok
-	void ProcessExplosions(int32 explosion);                 /// ok
-	void ProcessFireHydrant();                               /// ok
-	void ProcessFires(int32 entity);                         /// ok
-	void ProcessFrontEnd();                                  /// ok
-	void ProcessGarages();                                   /// ok
-	bool ProcessHelicopter(cVehicleParams *params);          /// ok
-	void ProcessHomeScriptObject(uint8 sound);               /// ok
-	void ProcessJumbo(cVehicleParams *);                     /// ok
-	void ProcessJumboAccel(CPlane *plane);                   /// ok
-	void ProcessJumboDecel(CPlane *plane);                   /// ok
-	void ProcessJumboFlying();                               /// ok
-	void ProcessJumboLanding(CPlane *plane);                 /// ok
-	void ProcessJumboTakeOff(CPlane *plane);                 /// ok
-	void ProcessJumboTaxi();                                 /// ok
-	void ProcessLaunderetteScriptObject(uint8 sound);        /// ok
-	void ProcessLoopingScriptObject(uint8 sound);            /// ok
-	void ProcessMissionAudio();                              /// ok
-	void ProcessModelCarEngine(cVehicleParams *params);      /// ok
-	void ProcessOneShotScriptObject(uint8 sound);            /// ok
-	void ProcessPed(CPhysical *ped);                         /// ok
-	void ProcessPedHeadphones(cPedParams *params);           /// ok
-	void ProcessPedOneShots(cPedParams *params);             // todo  later (weird)
-	void ProcessPhysical(int32 id);                          /// ok
-	void ProcessPlane(cVehicleParams *params);               /// ok
-	void ProcessPlayersVehicleEngine(cVehicleParams *params,
-	                                 CAutomobile *automobile); /// ok
-	void ProcessPoliceCellBeatingScriptObject(uint8 sound);    /// ok
-	void ProcessPornCinema(uint8 sound);                       /// ok
-	void ProcessProjectiles();                                 /// ok
-	void ProcessRainOnVehicle(cVehicleParams *params);         /// ok
-	void ProcessReverb() const;                                /// ok
-	bool ProcessReverseGear(cVehicleParams *params);           /// ok
-	void ProcessSawMillScriptObject(uint8 sound);              /// ok
-	void ProcessScriptObject(int32 id);                        /// ok
-	void ProcessShopScriptObject(uint8 sound);                 /// ok
-	void ProcessSpecial();                                     /// ok
-	bool ProcessTrainNoise(cVehicleParams *params);            /// ok
-	void ProcessVehicle(CVehicle *vehicle);                    /// ok
-	bool ProcessVehicleDoors(cVehicleParams *params);          /// ok
-	void ProcessVehicleEngine(cVehicleParams *params);         /// ok
-	void ProcessVehicleHorn(cVehicleParams *params);           /// ok
-	void ProcessVehicleOneShots(void *);                       // todo
-	bool ProcessVehicleReverseWarning(cVehicleParams *params); /// ok
-	bool ProcessVehicleRoadNoise(cVehicleParams *params);      /// ok
-	void ProcessVehicleSirenOrAlarm(cVehicleParams *params);   /// ok
-	void ProcessVehicleSkidding(cVehicleParams *params);       /// ok
-	void ProcessWaterCannon(int32);                            /// ok
-	void ProcessWeather(int32 id);                             /// ok
-	bool ProcessWetRoadNoise(cVehicleParams *params);          /// ok
-	void ProcessWorkShopScriptObject(uint8 sound);             /// ok
+	void ProcessActiveQueues();
+	bool ProcessAirBrakes(cVehicleParams *params);
+	void ProcessAirportScriptObject(uint8 sound);
+	bool ProcessBoatEngine(cVehicleParams *params);
+	bool ProcessBoatMovingOverWater(cVehicleParams *params);
+	void ProcessBridge();
+	void ProcessBridgeMotor();
+	void ProcessBridgeOneShots();
+	void ProcessBridgeWarning();
+	bool ProcessCarBombTick(cVehicleParams *params);
+	void ProcessCesna(cVehicleParams *params);
+	void ProcessCinemaScriptObject(uint8 sound);
+	void ProcessCrane();
+	void ProcessDocksScriptObject(uint8 sound);
+	bool ProcessEngineDamage(cVehicleParams *params);
+	void ProcessEntity(int32 sound);
+	void ProcessExplosions(int32 explosion);
+	void ProcessFireHydrant();
+	void ProcessFires(int32 entity);
+	void ProcessFrontEnd();
+	void ProcessGarages();
+	bool ProcessHelicopter(cVehicleParams *params);
+	void ProcessHomeScriptObject(uint8 sound);
+	void ProcessJumbo(cVehicleParams *);
+	void ProcessJumboAccel(CPlane *plane);
+	void ProcessJumboDecel(CPlane *plane);
+	void ProcessJumboFlying();
+	void ProcessJumboLanding(CPlane *plane);
+	void ProcessJumboTakeOff(CPlane *plane);
+	void ProcessJumboTaxi();
+	void ProcessLaunderetteScriptObject(uint8 sound);
+	void ProcessLoopingScriptObject(uint8 sound);
+	void ProcessMissionAudio();
+	void ProcessModelCarEngine(cVehicleParams *params);
+	void ProcessOneShotScriptObject(uint8 sound);
+	void ProcessPed(CPhysical *ped);
+	void ProcessPedHeadphones(cPedParams *params);
+	void ProcessPedOneShots(cPedParams *params);
+	void ProcessPhysical(int32 id);
+	void ProcessPlane(cVehicleParams *params);
+	void ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *automobile);
+	void ProcessPoliceCellBeatingScriptObject(uint8 sound);
+	void ProcessPornCinema(uint8 sound);
+	void ProcessProjectiles();
+	void ProcessRainOnVehicle(cVehicleParams *params);
+	void ProcessReverb() const;
+	bool ProcessReverseGear(cVehicleParams *params);
+	void ProcessSawMillScriptObject(uint8 sound);
+	void ProcessScriptObject(int32 id);
+	void ProcessShopScriptObject(uint8 sound);
+	void ProcessSpecial();
+	bool ProcessTrainNoise(cVehicleParams *params);
+	void ProcessVehicle(CVehicle *vehicle);
+	bool ProcessVehicleDoors(cVehicleParams *params);
+	void ProcessVehicleEngine(cVehicleParams *params);
+	void ProcessVehicleHorn(cVehicleParams *params);
+	void ProcessVehicleOneShots(cVehicleParams *params);
+	bool ProcessVehicleReverseWarning(cVehicleParams *params);
+	bool ProcessVehicleRoadNoise(cVehicleParams *params);
+	void ProcessVehicleSirenOrAlarm(cVehicleParams *params);
+	void ProcessVehicleSkidding(cVehicleParams *params);
+	void ProcessWaterCannon(int32);
+	void ProcessWeather(int32 id);
+	bool ProcessWetRoadNoise(cVehicleParams *params);
+	void ProcessWorkShopScriptObject(uint8 sound);
 
 	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);            /// ok
-	void ReportCrime(int32 crime, const CVector *pos); /// ok
-	void ResetAudioLogicTimers(uint32 timer);          /// ok
-	void ResetPoliceRadio();                           /// ok
-	void ResetTimers(uint32 time);                     /// ok
+	void ReportCollision(CEntity *entity1, CEntity *entity2, uint8 surface1, uint8 surface2,
+	                     float collisionPower, float intensity2);
+	void ReportCrime(int32 crime, const CVector *pos);
+	void ResetAudioLogicTimers(uint32 timer);
+	void ResetPoliceRadio();
+	void ResetTimers(uint32 time);
 
-	void Service();                                    /// ok
-	void ServiceCollisions();                          /// ok
-	void ServicePoliceRadio();                         /// ok
-	void ServicePoliceRadioChannel(int32 wantedLevel); /// ok
-	void ServiceSoundEffects();                        /// ok
-	int8 SetCurrent3DProvider(uint8 which);            /// ok
+	void Service();
+	void ServiceCollisions();
+	void ServicePoliceRadio();
+	void ServicePoliceRadioChannel(int32 wantedLevel);
+	void ServiceSoundEffects();
+	int8 SetCurrent3DProvider(uint8 which);
 	void SetDynamicAcousticModelingStatus(bool status);
 	void SetEffectsFadeVolume(uint8 volume) const;
 	void SetEffectsMasterVolume(uint8 volume) const;
 	void SetEntityStatus(int32 id, uint8 status);
-	uint32 SetLoopingCollisionRequestedSfxFreqAndGetVol(cAudioCollision *audioCollision); /// ok
+	uint32 SetLoopingCollisionRequestedSfxFreqAndGetVol(cAudioCollision *audioCollision);
 	void SetMissionAudioLocation(float x, float y, float z);
 	void SetMissionScriptPoliceAudio(int32 sfx) const;
 	void SetMonoMode(uint8); // todo (mobile)
 	void SetMusicFadeVolume(uint8 volume) const;
 	void SetMusicMasterVolume(uint8 volume) const;
 	void SetSpeakerConfig(int32 conf) const;
-	void SetUpLoopingCollisionSound(cAudioCollision *col, uint8 counter); /// ok
-	void SetUpOneShotCollisionSound(cAudioCollision *col);                /// ok
-	bool SetupCrimeReport();                                              /// ok
-	bool SetupJumboEngineSound(uint8 vol, int32 freq);                    /// ok
-	bool SetupJumboFlySound(uint8 emittingVol);                           /// ok
-	bool SetupJumboRumbleSound(uint8 emittingVol);                        /// ok
-	bool SetupJumboTaxiSound(uint8 vol);                                  /// ok
-	bool SetupJumboWhineSound(uint8 emittingVol, int32 freq);             /// ok
-	void SetupPedComments(cPedParams *params, uint32 sound);              /// ok
-	void SetupSuspectLastSeenReport();                                    /// ok
+	void SetUpLoopingCollisionSound(cAudioCollision *col, uint8 counter);
+	void SetUpOneShotCollisionSound(cAudioCollision *col);
+	bool SetupCrimeReport();
+	bool SetupJumboEngineSound(uint8 vol, int32 freq);
+	bool SetupJumboFlySound(uint8 emittingVol);
+	bool SetupJumboRumbleSound(uint8 emittingVol);
+	bool SetupJumboTaxiSound(uint8 vol);
+	bool SetupJumboWhineSound(uint8 emittingVol, int32 freq);
+	void SetupPedComments(cPedParams *params, uint32 sound);
+	void SetupSuspectLastSeenReport();
 
 	void Terminate();
 	void TranslateEntity(CVector *v1, CVector *v2) const;
@@ -604,11 +614,10 @@ public:
 	bool UsesSirenSwitching(int32 model) const;
 
 	// only used in pc
-	void AdjustSamplesVolume(); /// ok
-	uint8 ComputeEmittingVolume(uint8 emittingVolume, float intensity,
-	                            float dist); /// ok
+	void AdjustSamplesVolume();
+	uint8 ComputeEmittingVolume(uint8 emittingVolume, float intensity, float dist);
 };
 
 static_assert(sizeof(cAudioManager) == 19220, "cAudioManager: error");
 
-extern cAudioManager &AudioManager;
+extern cAudioManager AudioManager;
diff --git a/src/audio/AudioScriptObject.cpp b/src/audio/AudioScriptObject.cpp
index 0ae3834a..da9e1d2e 100644
--- a/src/audio/AudioScriptObject.cpp
+++ b/src/audio/AudioScriptObject.cpp
@@ -61,7 +61,7 @@ cAudioScriptObject::SaveAllAudioScriptObjects(uint8 *buf, uint32 *size)
 	INITSAVEBUF
 
 	int32 pool_size = CPools::GetAudioScriptObjectPool()->GetNoOfUsedSpaces();
-	*size = SAVE_HEADER_SIZE + pool_size * (sizeof(cAudioScriptObject) + sizeof(int32));
+	*size = SAVE_HEADER_SIZE + sizeof(int32) + pool_size * (sizeof(cAudioScriptObject) + sizeof(int32));
 	WriteSaveHeader(buf, 'A', 'U', 'D', '\0', *size - SAVE_HEADER_SIZE);
 	WriteSaveBuf(buf, pool_size);
 
diff --git a/src/audio/PoliceRadio.cpp b/src/audio/PoliceRadio.cpp
index d162ca4c..255d7026 100644
--- a/src/audio/PoliceRadio.cpp
+++ b/src/audio/PoliceRadio.cpp
@@ -1,789 +1,792 @@
-#include "common.h"
-#include "patcher.h"
-#include "DMAudio.h"
-#include "AudioManager.h"
-#include "AudioSamples.h"
-#include "MusicManager.h"
-#include "PoliceRadio.h"
-#include "PlayerPed.h"
-#include "sampman.h"
-#include "Zones.h"
-#include "Vehicle.h"
-#include "World.h"
-
-const int maxVolume = 127;
-const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples);
-const int policeChannel = channels + 1;
-
-struct tPoliceRadioZone {
-	char m_aName[8];
-	uint32 m_nSampleIndex;
-	int32 field_12;
-};
-
-tPoliceRadioZone (&ZoneSfx)[NUMAUDIOZONES] = *(tPoliceRadioZone(*)[NUMAUDIOZONES])*(uintptr*)0x880240;
-char *SubZo2Label = (char*)0x6E9918;
-char *SubZo3Label = (char*)0x6E9870;
-
-int32 &g_nMissionAudioSfx = *(int32*)0x60ED84;
-int8 &g_nMissionAudioPlayingStatus = *(int8*)0x60ED88;
-uint8 &gSpecialSuspectLastSeenReport = *(uint8*)0x95CD4D;
-uint32 (&gMinTimeToNextReport)[NUM_CRIME_TYPES] = *(uint32(*)[NUM_CRIME_TYPES])*(uintptr*)0x8E2828;
-
-void
-cAudioManager::InitialisePoliceRadioZones()
-{
-	for (int32 i = 0; i < NUMAUDIOZONES; i++)
-		memset(ZoneSfx[i].m_aName, 0, 8);
-
-#define SETZONESFX(i, name, sample) \
-	strcpy(ZoneSfx[i].m_aName, name); \
-	ZoneSfx[i].m_nSampleIndex = sample;
-
-	SETZONESFX(0, "HOSPI_2", SFX_POLICE_RADIO_ROCKFORD);
-	SETZONESFX(1, "CONSTRU", SFX_POLICE_RADIO_FORT_STAUNTON);
-	SETZONESFX(2, "STADIUM", SFX_POLICE_RADIO_ASPATRIA);
-	SETZONESFX(3, "YAKUSA", SFX_POLICE_RADIO_TORRINGTON);
-	SETZONESFX(4, "SHOPING", SFX_POLICE_RADIO_BEDFORD_POINT);
-	SETZONESFX(5, "COM_EAS", SFX_POLICE_RADIO_NEWPORT);
-	SETZONESFX(6, "PARK", SFX_POLICE_RADIO_BELLEVILLE_PARK);
-	SETZONESFX(7, "UNIVERS", SFX_POLICE_RADIO_LIBERTY_CAMPUS);
-	SETZONESFX(8, "BIG_DAM", SFX_POLICE_RADIO_COCHRANE_DAM);
-	SETZONESFX(9, "SUB_IND", SFX_POLICE_RADIO_PIKE_CREEK);
-	SETZONESFX(10, "SWANKS", SFX_POLICE_RADIO_CEDAR_GROVE);
-	SETZONESFX(11, "PROJECT", SFX_POLICE_RADIO_WICHITA_GARDENS);
-	SETZONESFX(12, "AIRPORT", SFX_POLICE_RADIO_FRANCIS_INTERNATIONAL_AIRPORT);
-	SETZONESFX(13, "PORT_W", SFX_POLICE_RADIO_CALLAHAN_POINT);
-	SETZONESFX(14, "PORT_S", SFX_POLICE_RADIO_ATLANTIC_QUAYS);
-	SETZONESFX(15, "PORT_E", SFX_POLICE_RADIO_PORTLAND_HARBOUR);
-	SETZONESFX(16, "PORT_I", SFX_POLICE_RADIO_TRENTON);
-	SETZONESFX(17, "CHINA", SFX_POLICE_RADIO_CHINATOWN);
-	SETZONESFX(18, "REDLIGH", SFX_POLICE_RADIO_RED_LIGHT_DISTRICT);
-	SETZONESFX(19, "TOWERS", SFX_POLICE_RADIO_HEPBURN_HEIGHTS);
-	SETZONESFX(20, "LITTLEI", SFX_POLICE_RADIO_SAINT_MARKS);
-	SETZONESFX(21, "HARWOOD", SFX_POLICE_RADIO_HARWOOD);
-	SETZONESFX(22, "EASTBAY", SFX_POLICE_RADIO_PORTLAND_BEACH);
-	SETZONESFX(23, "S_VIEW", SFX_POLICE_RADIO_PORTLAND_STRAIGHTS);
-	SETZONESFX(24, "CITYZON", SFX_POLICE_RADIO_LIBERTY_CITY);
-	SETZONESFX(25, "IND_ZON", SFX_POLICE_RADIO_PORTLAND);
-	SETZONESFX(26, "COM_ZON", SFX_POLICE_RADIO_STAUNTON_ISLAND);
-	SETZONESFX(27, "SUB_ZON", SFX_POLICE_RADIO_SHORESIDE_VALE);
-	SETZONESFX(28, "SUB_ZO2", SFX_POLICE_RADIO_SHORESIDE_VALE);
-	SETZONESFX(29, "SUB_ZO3", SFX_POLICE_RADIO_SHORESIDE_VALE);
-	SETZONESFX(30, "A", SFX_POLICE_RADIO_ROCKFORD);
-	SETZONESFX(31, "A", SFX_POLICE_RADIO_ROCKFORD);
-	SETZONESFX(32, "A", SFX_POLICE_RADIO_ROCKFORD);
-	SETZONESFX(33, "A", SFX_POLICE_RADIO_ROCKFORD);
-	SETZONESFX(34, "A", SFX_POLICE_RADIO_ROCKFORD);
-
-#undef SETZONESFX
-
-	strcpy(SubZo2Label, "SUB_ZO2");
-	strcpy(SubZo3Label, "SUB_ZO3");
-}
-
-void
-cAudioManager::InitialisePoliceRadio()
-{
-	m_sPoliceRadioQueue.policeChannelTimer = 0;
-	m_sPoliceRadioQueue.policeChannelTimerSeconds = 0;
-	m_sPoliceRadioQueue.policeChannelCounterSeconds = 0;
-	for (int32 i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++)
-		m_sPoliceRadioQueue.crimes[i].type = 0;
-
-	SampleManager.SetChannelReverbFlag(policeChannel, 0);
-	gSpecialSuspectLastSeenReport = false;
-	for (int32 i = 0; i < ARRAY_SIZE(gMinTimeToNextReport); i++)
-		gMinTimeToNextReport[i] = m_FrameCounter;
-}
-
-void
-cAudioManager::ResetPoliceRadio()
-{
-	if (!m_bIsInitialised) return;
-	if (SampleManager.GetChannelUsedFlag(policeChannel)) SampleManager.StopChannel(policeChannel);
-	InitialisePoliceRadio();
-}
-
-void
-cAudioManager::SetMissionScriptPoliceAudio(int32 sfx) const
-{
-	if (!m_bIsInitialised) return;
-	if (g_nMissionAudioPlayingStatus != 1) {
-		g_nMissionAudioPlayingStatus = 0;
-		g_nMissionAudioSfx = sfx;
-	}
-}
-
-int8
-cAudioManager::GetMissionScriptPoliceAudioPlayingStatus() const
-{
-	return g_nMissionAudioPlayingStatus;
-}
-
-void
-cAudioManager::DoPoliceRadioCrackle()
-{
-	m_sQueueSample.m_nEntityIndex = m_nPoliceChannelEntity;
-	m_sQueueSample.m_counter = 0;
-	m_sQueueSample.m_nSampleIndex = SFX_POLICE_RADIO_CRACKLE;
-	m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
-	m_sQueueSample.m_bIsDistant = true;
-	m_sQueueSample.field_16 = 10;
-	m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_POLICE_RADIO_CRACKLE);
-	m_sQueueSample.m_bVolume = m_anRandomTable[2] % 20 + 15;
-	m_sQueueSample.m_nLoopCount = 0;
-	m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume;
-	m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(SFX_POLICE_RADIO_CRACKLE);
-	m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(SFX_POLICE_RADIO_CRACKLE);
-	m_sQueueSample.field_56 = 0;
-	m_sQueueSample.m_bReverbFlag = false;
-	m_sQueueSample.m_bOffset = 63;
-	m_sQueueSample.field_76 = 3;
-	m_sQueueSample.m_bRequireReflection = false;
-	AddSampleToRequestedQueue();
-}
-
-void
-cAudioManager::ServicePoliceRadio()
-{
-	int32 wantedLevel = 0; // bug?;
-	static uint32 nLastSeen = 300;
-
-	if (!m_bIsInitialised) return;
-
-	if (!m_bUserPause) {
-		bool crimeReport = SetupCrimeReport();
-		wantedLevel = FindPlayerPed()->m_pWanted->m_nWantedLevel;
-		if (!crimeReport) {
-			if (wantedLevel) {
-				if (nLastSeen) {
-					--nLastSeen;
-				} else {
-					nLastSeen = m_anRandomTable[1] % 1000 + 2000;
-					SetupSuspectLastSeenReport();
-				}
-			}
-		}
-	}
-	ServicePoliceRadioChannel(wantedLevel);
-}
-
-void
-cAudioManager::ServicePoliceRadioChannel(int32 wantedLevel)
-{
-	bool processed = false;
-	uint32 sample;
-	int32 freq;
-
-	static int cWait = 0;
-	static bool bChannelOpen = false;
-	static uint8 bMissionAudioPhysicalPlayingStatus = 0;
-	static int32 PoliceChannelFreq = 5500;
-
-	if (!m_bIsInitialised) return;
-
-	if (m_bUserPause) {
-		if (SampleManager.GetChannelUsedFlag(policeChannel)) SampleManager.StopChannel(policeChannel);
-		if (g_nMissionAudioSfx != TOTAL_AUDIO_SAMPLES && bMissionAudioPhysicalPlayingStatus == 1 &&
-			SampleManager.IsStreamPlaying(1)) {
-			SampleManager.PauseStream(1, 1);
-		}
-	} else {
-		if (m_bPreviousUserPause && g_nMissionAudioSfx != TOTAL_AUDIO_SAMPLES &&
-			bMissionAudioPhysicalPlayingStatus == 1) {
-			SampleManager.PauseStream(0, 1);
-		}
-		if (m_sPoliceRadioQueue.policeChannelTimer == 0) bChannelOpen = false;
-		if (cWait) {
-			--cWait;
-			return;
-		}
-		if (g_nMissionAudioSfx != TOTAL_AUDIO_SAMPLES && !bChannelOpen) {
-			if (g_nMissionAudioPlayingStatus) {
-				if (g_nMissionAudioPlayingStatus == 1 && !bMissionAudioPhysicalPlayingStatus &&
-					SampleManager.IsStreamPlaying(1)) {
-					bMissionAudioPhysicalPlayingStatus = 1;
-				}
-				if (bMissionAudioPhysicalPlayingStatus == 1) {
-					if (SampleManager.IsStreamPlaying(1)) {
-						DoPoliceRadioCrackle();
-					} else {
-						bMissionAudioPhysicalPlayingStatus = 2;
-						g_nMissionAudioPlayingStatus = 2;
-						g_nMissionAudioSfx = TOTAL_AUDIO_SAMPLES;
-						cWait = 30;
-					}
-					return;
-				}
-			} else if (!SampleManager.GetChannelUsedFlag(policeChannel)) {
-				SampleManager.PreloadStreamedFile(g_nMissionAudioSfx, 1);
-				SampleManager.SetStreamedVolumeAndPan(maxVolume, 63, 1, 1);
-				SampleManager.StartPreloadedStreamedFile(1);
-				g_nMissionAudioPlayingStatus = 1;
-				bMissionAudioPhysicalPlayingStatus = 0;
-				return;
-			}
-		}
-		if (bChannelOpen) DoPoliceRadioCrackle();
-		if ((g_nMissionAudioSfx == TOTAL_AUDIO_SAMPLES || g_nMissionAudioPlayingStatus != 1) &&
-			!SampleManager.GetChannelUsedFlag(policeChannel) && m_sPoliceRadioQueue.policeChannelTimer) {
-			if (m_sPoliceRadioQueue.policeChannelTimer) {
-				sample = m_sPoliceRadioQueue.crimesSamples[m_sPoliceRadioQueue.policeChannelCounterSeconds];
-				m_sPoliceRadioQueue.policeChannelTimer--;
-				m_sPoliceRadioQueue.policeChannelCounterSeconds = (m_sPoliceRadioQueue.policeChannelCounterSeconds + 1) % 60;
-			} else {
-				sample = TOTAL_AUDIO_SAMPLES;
-			}
-			if (!wantedLevel) {
-				if (gSpecialSuspectLastSeenReport) {
-					gSpecialSuspectLastSeenReport = 0;
-				} else if (((sample >= SFX_POLICE_RADIO_MESSAGE_NOISE_1) && (sample <= SFX_POLICE_RADIO_MESSAGE_NOISE_3)) || sample == TOTAL_AUDIO_SAMPLES) {
-					bChannelOpen = false;
-					processed = true;
-				}
-			}
-			if (sample == TOTAL_AUDIO_SAMPLES) {
-				if (!processed) cWait = 30;
-			} else {
-				SampleManager.InitialiseChannel(policeChannel, sample, 0);
-				switch (sample) {
-				case SFX_POLICE_RADIO_MESSAGE_NOISE_1:
-				case SFX_POLICE_RADIO_MESSAGE_NOISE_2:
-				case SFX_POLICE_RADIO_MESSAGE_NOISE_3:
-					freq = m_anRandomTable[4] % 2000 + 10025;
-					bChannelOpen = bChannelOpen == false;
-					break;
-				default: freq = SampleManager.GetSampleBaseFrequency(sample); break;
-				}
-				PoliceChannelFreq = freq;
-				SampleManager.SetChannelFrequency(policeChannel, freq);
-				SampleManager.SetChannelVolume(policeChannel, 100);
-				SampleManager.SetChannelPan(policeChannel, 63);
-				SampleManager.SetChannelLoopCount(policeChannel, 1);
-				SampleManager.SetChannelLoopPoints(policeChannel, 0, -1);
-				SampleManager.StartChannel(policeChannel);
-			}
-			if (processed) ResetPoliceRadio();
-		}
-	}
-}
-
-bool
-cAudioManager::SetupCrimeReport()
-{
-	int16 audioZoneId;
-	CZone *zone;
-	float rangeX;
-	float rangeY;
-	float halfX;
-	float halfY;
-	float quarterX;
-	float quarterY;
-	int i;
-	int32 sampleIndex;
-	bool processed = false;
-
-	if (MusicManager.m_nMusicMode == MUSICMODE_CUTSCENE) return false;
-
-	if (60 - m_sPoliceRadioQueue.policeChannelTimer <= 9) {
-		AgeCrimes();
-		return true;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++) {
-		if (m_sPoliceRadioQueue.crimes[i].type != CRIME_NONE)
-			break;
-	}
-
-	if (i == ARRAY_SIZE(m_sPoliceRadioQueue.crimes)) return false;
-	audioZoneId = CTheZones::FindAudioZone(&m_sPoliceRadioQueue.crimes[i].position);
-	if (audioZoneId >= 0 && audioZoneId < NUMAUDIOZONES) {
-		zone = &CTheZones::ZoneArray[CTheZones::AudioZoneArray[audioZoneId]];
-		for (int j = 0; j < NUMAUDIOZONES; j++) {
-			if (strcmp(zone->name, ZoneSfx[j].m_aName) == 0) {
-				sampleIndex = ZoneSfx[j].m_nSampleIndex;
-				m_sPoliceRadioQueue.Add(m_anRandomTable[4] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-				m_sPoliceRadioQueue.Add(m_anRandomTable[0] % 3 + SFX_WEVE_GOT);
-				m_sPoliceRadioQueue.Add(m_anRandomTable[1] % 2 + SFX_A_10_1);
-				switch (m_sPoliceRadioQueue.crimes[i].type) {
-				case CRIME_PED_BURNED: m_sPoliceRadioQueue.crimes[i].type = CRIME_HIT_PED; break;
-				case CRIME_COP_BURNED: m_sPoliceRadioQueue.crimes[i].type = CRIME_HIT_COP; break;
-				case CRIME_VEHICLE_BURNED: m_sPoliceRadioQueue.crimes[i].type = CRIME_STEAL_CAR; break;
-				case CRIME_DESTROYED_CESSNA: m_sPoliceRadioQueue.crimes[i].type = CRIME_SHOOT_HELI; break;
-				default: break;
-				}
-				m_sPoliceRadioQueue.Add(m_sPoliceRadioQueue.crimes[i].type + SFX_CRIME_1 - 1);
-				m_sPoliceRadioQueue.Add(SFX_IN);
-				if (sampleIndex == SFX_POLICE_RADIO_SHORESIDE_VALE &&
-					(strcmp(zone->name, SubZo2Label) == 0 || strcmp(zone->name, SubZo3Label) == 0)) {
-					m_sPoliceRadioQueue.Add(SFX_NORTH);
-					m_sPoliceRadioQueue.Add(SFX_EAST);
-				} else {
-					rangeX = zone->maxx - zone->minx;
-					rangeY = zone->maxy - zone->miny;
-					halfX = 0.5f * rangeX + zone->minx;
-					halfY = 0.5f * rangeY + zone->miny;
-					quarterX = 0.25f * rangeX;
-					quarterY = 0.25f * rangeY;
-
-					if (m_sPoliceRadioQueue.crimes[i].position.y > halfY + quarterY) {
-						m_sPoliceRadioQueue.Add(SFX_NORTH);
-						processed = true;
-					} else if (m_sPoliceRadioQueue.crimes[i].position.y < halfY - quarterY) {
-						m_sPoliceRadioQueue.Add(SFX_SOUTH);
-						processed = true;
-					}
-
-					if (m_sPoliceRadioQueue.crimes[i].position.x > halfX + quarterX)
-						m_sPoliceRadioQueue.Add(SFX_EAST);
-					else if (m_sPoliceRadioQueue.crimes[i].position.x < halfX - quarterX)
-						m_sPoliceRadioQueue.Add(SFX_WEST);
-					else if (!processed)
-						m_sPoliceRadioQueue.Add(SFX_CENTRAL);
-
-					m_sPoliceRadioQueue.Add(sampleIndex);
-					m_sPoliceRadioQueue.Add(m_anRandomTable[2] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-					m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
-				}
-				break;
-			}
-		}
-	}
-	m_sPoliceRadioQueue.crimes[i].type = CRIME_NONE;
-	AgeCrimes();
-	return true;
-}
-
-void
-cAudioManager::SetupSuspectLastSeenReport()
-{
-	CVehicle *veh;
-	uint8 color1;
-	int32 main_color;
-	int32 sample;
-
-	int32 color_pre_modifier;
-	int32 color_post_modifier;
-
-	const int32 gCarColourTable[][3] = {
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLACK, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_WHITE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_BRIGHT, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_BLUE, SFX_POLICE_RADIO_GREY},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-#else
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-#endif
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-#else
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-#endif
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-#else
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-#endif
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-#else
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-#endif
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-#else
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-#endif
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_PURPLE, SFX_POLICE_RADIO_BLUE},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-#else
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-#endif
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, SFX_POLICE_RADIO_GREY},
-#else
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-#endif
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-#else
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-#endif
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-#ifdef FIX_BUGS
-		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-#else
-		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
-#endif
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
-		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES}
-	};
-
-	if (MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE) {
-		veh = FindPlayerVehicle();
-		if (veh != nil) {
-			if (60 - m_sPoliceRadioQueue.policeChannelTimer > 9) {
-				color1 = veh->m_currentColour1;
-				if (color1 >= ARRAY_SIZE(gCarColourTable)) {
-					debug("\n *** UNKNOWN CAR COLOUR %d *** ", color1);
-				} else {
-					main_color = gCarColourTable[color1][1];
-					color_pre_modifier = gCarColourTable[color1][0];
-					color_post_modifier = gCarColourTable[color1][2];
-					switch (veh->m_modelIndex) {
-#ifdef FIX_BUGS
-					case MI_COLUMB:
-						main_color = SFX_POLICE_RADIO_BLUE;
-						color_pre_modifier = color_post_modifier = TOTAL_AUDIO_SAMPLES;
-#endif
-					case MI_LANDSTAL:
-					case MI_BLISTA: sample = SFX_POLICE_RADIO_CRUISER; break;
-#ifdef FIX_BUGS
-					case MI_YARDIE:
-						color_pre_modifier = TOTAL_AUDIO_SAMPLES;
-						main_color = SFX_POLICE_RADIO_RED;
-						color_post_modifier = SFX_POLICE_RADIO_YELLOW;
-						sample = SFX_POLICE_RADIO_CONVERTIBLE; break;
-					case MI_DIABLOS:
-						main_color = SFX_POLICE_RADIO_BLACK;
-#endif
-					case MI_IDAHO:
-					case MI_STALLION: sample = SFX_POLICE_RADIO_CONVERTIBLE; break;
-#ifdef FIX_BUGS
-					case MI_YAKUZA:
-						color_pre_modifier = TOTAL_AUDIO_SAMPLES;
-						main_color = SFX_POLICE_RADIO_SILVER;
-						color_post_modifier = SFX_POLICE_RADIO_RED;
-#endif
-					case MI_STINGER:
-					case MI_INFERNUS:
-					case MI_CHEETAH:
-					case MI_BANSHEE: sample = SFX_POLICE_RADIO_SPORTS_CAR; break;
-#ifdef FIX_BUGS
-					case MI_MAFIA:
-						color_pre_modifier = color_post_modifier = TOTAL_AUDIO_SAMPLES;
-						main_color = SFX_POLICE_RADIO_GREY;
-					case MI_KURUMA:
-#endif
-					case MI_PEREN:
-					case MI_SENTINEL:
-					case MI_FBICAR: sample = SFX_POLICE_RADIO_SALOON; break;
-					case MI_PATRIOT:
-					case MI_BOBCAT: sample = SFX_POLICE_RADIO_PICKUP; break;
-					case MI_FIRETRUCK: sample = SFX_POLICE_RADIO_FIRE_TRUCK; break;
-#ifdef FIX_BUGS
-					case MI_LINERUN:
-					case MI_FLATBED:
-#endif
-					case MI_TRASH:
-					case MI_BARRACKS: sample = SFX_POLICE_RADIO_TRUCK; break;
-					case MI_STRETCH: sample = SFX_POLICE_RADIO_LIMO; break;
-#ifdef FIX_BUGS
-					case MI_CORPSE:
-#endif
-					case MI_MANANA:
-					case MI_ESPERANT: sample = SFX_POLICE_RADIO_2_DOOR; break;
-#ifdef FIX_BUGS
-					case MI_HOODS:
-						color_pre_modifier = TOTAL_AUDIO_SAMPLES;
-						main_color = SFX_POLICE_RADIO_BLUE;
-						color_post_modifier = SFX_POLICE_RADIO_GREEN;
-					case MI_BELLYUP:
-					case MI_YANKEE:
-					case MI_TOYZ:
-					case MI_MRWONGS:
-					case MI_PANLANT:
-#endif
-					case MI_PONY:
-					case MI_MULE:
-					case MI_MOONBEAM:
-					case MI_ENFORCER:
-					case MI_SECURICA:
-					case MI_RUMPO: sample = SFX_POLICE_RADIO_VAN; break;
-					case MI_AMBULAN: sample = SFX_POLICE_RADIO_AMBULANCE; break;
-					case MI_TAXI:
-					case MI_CABBIE:
-					case MI_BORGNINE: sample = SFX_POLICE_RADIO_TAXI; break;
-					case MI_MRWHOOP:
-						sample = SFX_POLICE_RADIO_ICE_CREAM_VAN;
-						break;
-					case MI_BFINJECT: sample = SFX_POLICE_RADIO_BUGGY; break;
-					case MI_POLICE: sample = SFX_POLICE_RADIO_POLICE_CAR; break;
-#ifdef FIX_BUGS
-					case MI_SPEEDER:
-					case MI_REEFER:
-					case MI_GHOST:
-#endif
-					case MI_PREDATOR: sample = SFX_POLICE_RADIO_BOAT; break;
-					case MI_BUS:
-					case MI_COACH: sample = SFX_POLICE_RADIO_BUS; break;
-					case MI_RHINO:
-						sample = SFX_POLICE_RADIO_TANK;
-						main_color = TOTAL_AUDIO_SAMPLES;
-						color_post_modifier = TOTAL_AUDIO_SAMPLES;
-						break;
-					case MI_TRAIN:
-						sample = SFX_POLICE_RADIO_SUBWAY_CAR;
-						main_color = TOTAL_AUDIO_SAMPLES;
-						color_post_modifier = TOTAL_AUDIO_SAMPLES;
-
-						break;
-					default:
-						debug("\n *** UNKNOWN CAR MODEL INDEX %d *** ", veh->m_modelIndex);
-						return;
-					}
-					m_sPoliceRadioQueue.Add(m_anRandomTable[4] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-					m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_SUSPECT);
-					if (m_anRandomTable[3] % 2) 
-						m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_LAST_SEEN);
-#ifdef FIX_BUGS
-					if (main_color == SFX_POLICE_RADIO_ORANGE && color_pre_modifier == TOTAL_AUDIO_SAMPLES)
-#else
-					if (main_color == SFX_POLICE_RADIO_ORANGE)
-#endif
-						m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_IN_AN);
-					else
-						m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_IN_A);
-					if (color_pre_modifier != TOTAL_AUDIO_SAMPLES)
-						m_sPoliceRadioQueue.Add(color_pre_modifier);
-					if (main_color != TOTAL_AUDIO_SAMPLES)
-						m_sPoliceRadioQueue.Add(main_color);
-					if (color_post_modifier != TOTAL_AUDIO_SAMPLES)
-						m_sPoliceRadioQueue.Add(color_post_modifier);
-					m_sPoliceRadioQueue.Add(sample);
-					m_sPoliceRadioQueue.Add(m_anRandomTable[0] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-					m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
-				}
-			}
-		} else if (60 - m_sPoliceRadioQueue.policeChannelTimer > 4) {
-			m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-			m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_SUSPECT);
-			m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_ON_FOOT);
-			m_sPoliceRadioQueue.Add(m_anRandomTable[0] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-			m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
-		}
-	}
-}
-
-
-
-void
-cAudioManager::ReportCrime(int32 type, const CVector *pos)
-{
-	int32 lastCrime = ARRAY_SIZE(m_sPoliceRadioQueue.crimes);
-	if (m_bIsInitialised && MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 &&
-		(type > CRIME_NONE || type < NUM_CRIME_TYPES) && m_FrameCounter >= gMinTimeToNextReport[type]) {
-		for (int32 i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++) {
-			if (m_sPoliceRadioQueue.crimes[i].type) {
-				if (m_sPoliceRadioQueue.crimes[i].type == type) {
-					m_sPoliceRadioQueue.crimes[i].position = *pos;
-					m_sPoliceRadioQueue.crimes[i].timer = 0;
-					return;
-				}
-			} else {
-				lastCrime = i;
-			}
-		}
-
-		if (lastCrime < ARRAY_SIZE(m_sPoliceRadioQueue.crimes)) {
-			m_sPoliceRadioQueue.crimes[lastCrime].type = type;
-			m_sPoliceRadioQueue.crimes[lastCrime].position = *pos;
-			m_sPoliceRadioQueue.crimes[lastCrime].timer = 0;
-			gMinTimeToNextReport[type] = m_FrameCounter + 500;
-		}
-	}
-}
-
-void
-cAudioManager::PlaySuspectLastSeen(float x, float y, float z)
-{
-	int16 audioZone;
-	CZone *zone;
-	float rangeX;
-	float rangeY;
-	float halfX;
-	float halfY;
-	float quarterX;
-	float quarterY;
-	int32 sample;
-	bool processed = false;
-	CVector vec = CVector(x, y, z);
-
-	if (!m_bIsInitialised) return;
-
-	if (MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE && 60 - m_sPoliceRadioQueue.policeChannelTimer > 9) {
-		audioZone = CTheZones::FindAudioZone(&vec);
-		if (audioZone >= 0 && audioZone < NUMAUDIOZONES) {
-			zone = &CTheZones::ZoneArray[CTheZones::AudioZoneArray[audioZone]];
-			for (int i = 0; i < NUMAUDIOZONES; i++) {
-				if (strcmp(zone->name, ZoneSfx[i].m_aName) == 0) {
-					sample = ZoneSfx[i].m_nSampleIndex;
-					m_sPoliceRadioQueue.Add(m_anRandomTable[4] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-					m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_SUSPECT);
-					m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_LAST_SEEN);
-					m_sPoliceRadioQueue.Add(SFX_IN);
-					if (sample == SFX_POLICE_RADIO_SHORESIDE_VALE &&
-						(strcmp(zone->name, SubZo2Label) == 0 ||
-							strcmp(zone->name, SubZo3Label) == 0)) {
-						m_sPoliceRadioQueue.Add(SFX_NORTH);
-						m_sPoliceRadioQueue.Add(SFX_EAST);
-					} else {
-						rangeX = zone->maxx - zone->minx;
-						rangeY = zone->maxy - zone->miny;
-						halfX = 0.5f * rangeX + zone->minx;
-						halfY = 0.5f * rangeY + zone->miny;
-						quarterX = 0.25f * rangeX;
-						quarterY = 0.25f * rangeY;
-
-						if (vec.y > halfY + quarterY) {
-							m_sPoliceRadioQueue.Add(SFX_NORTH);
-							processed = true;
-						} else if (vec.y < halfY - quarterY) {
-							m_sPoliceRadioQueue.Add(SFX_SOUTH);
-							processed = true;
-						}
-
-						if (vec.x > halfX + quarterX)
-							m_sPoliceRadioQueue.Add(SFX_EAST);
-						else if (vec.x < halfX - quarterX)
-							m_sPoliceRadioQueue.Add(SFX_WEST);
-						else if (!processed)
-							m_sPoliceRadioQueue.Add(SFX_CENTRAL);
-					}
-					m_sPoliceRadioQueue.Add(sample);
-					m_sPoliceRadioQueue.Add(m_anRandomTable[2] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
-					m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
-					gSpecialSuspectLastSeenReport = true;
-					break;
-				}
-			}
-		}
-	}
-}
-
-void
-cAudioManager::AgeCrimes()
-{
-	for (uint8 i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++) {
-		if (m_sPoliceRadioQueue.crimes[i].type != CRIME_NONE) {
-			if (++m_sPoliceRadioQueue.crimes[i].timer > 1500) m_sPoliceRadioQueue.crimes[i].type = CRIME_NONE;
-		}
-	}
-}
-
-STARTPATCHES
-InjectHook(0x580AF0, &cAudioManager::AgeCrimes, PATCH_JUMP);
-InjectHook(0x57F060, &cAudioManager::DoPoliceRadioCrackle, PATCH_JUMP);
-InjectHook(0x57F050, &cAudioManager::GetMissionScriptPoliceAudioPlayingStatus, PATCH_JUMP);
-InjectHook(0x57EEC0, &cAudioManager::InitialisePoliceRadio, PATCH_JUMP);
-InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP);
-InjectHook(0x580500, &cAudioManager::PlaySuspectLastSeen, PATCH_JUMP);
-InjectHook(0x5803D0, &cAudioManager::ReportCrime, PATCH_JUMP);
-InjectHook(0x57EFF0, &cAudioManager::ResetPoliceRadio, PATCH_JUMP);
-InjectHook(0x57F110, &cAudioManager::ServicePoliceRadio, PATCH_JUMP);
-InjectHook(0x57F1B0, &cAudioManager::ServicePoliceRadioChannel, PATCH_JUMP);
-InjectHook(0x57F020, &cAudioManager::SetMissionScriptPoliceAudio, PATCH_JUMP);
-InjectHook(0x57F5B0, &cAudioManager::SetupCrimeReport, PATCH_JUMP);
-InjectHook(0x57FCC0, &cAudioManager::SetupSuspectLastSeenReport, PATCH_JUMP);
-ENDPATCHES
+#include "common.h"
+#include "patcher.h"
+#include "DMAudio.h"
+#include "AudioManager.h"
+#include "AudioSamples.h"
+#include "MusicManager.h"
+#include "PoliceRadio.h"
+#include "PlayerPed.h"
+#include "sampman.h"
+#include "Zones.h"
+#include "Vehicle.h"
+#include "World.h"
+
+const int maxVolume = 127;
+const int channels = ARRAY_SIZE(cAudioManager::m_asActiveSamples);
+const int policeChannel = channels + 1;
+
+struct tPoliceRadioZone {
+	char m_aName[8];
+	uint32 m_nSampleIndex;
+	int32 field_12;
+};
+
+tPoliceRadioZone (&ZoneSfx)[NUMAUDIOZONES] = *(tPoliceRadioZone(*)[NUMAUDIOZONES])*(uintptr*)0x880240;
+char *SubZo2Label = (char*)0x6E9918;
+char *SubZo3Label = (char*)0x6E9870;
+
+int32 &g_nMissionAudioSfx = *(int32*)0x60ED84;
+int8 &g_nMissionAudioPlayingStatus = *(int8*)0x60ED88;
+uint8 &gSpecialSuspectLastSeenReport = *(uint8*)0x95CD4D;
+uint32 (&gMinTimeToNextReport)[NUM_CRIME_TYPES] = *(uint32(*)[NUM_CRIME_TYPES])*(uintptr*)0x8E2828;
+
+void
+cAudioManager::InitialisePoliceRadioZones()
+{
+	for (int32 i = 0; i < NUMAUDIOZONES; i++)
+		memset(ZoneSfx[i].m_aName, 0, 8);
+
+#define SETZONESFX(i, name, sample) \
+	strcpy(ZoneSfx[i].m_aName, name); \
+	ZoneSfx[i].m_nSampleIndex = sample;
+
+	SETZONESFX(0, "HOSPI_2", SFX_POLICE_RADIO_ROCKFORD);
+	SETZONESFX(1, "CONSTRU", SFX_POLICE_RADIO_FORT_STAUNTON);
+	SETZONESFX(2, "STADIUM", SFX_POLICE_RADIO_ASPATRIA);
+	SETZONESFX(3, "YAKUSA", SFX_POLICE_RADIO_TORRINGTON);
+	SETZONESFX(4, "SHOPING", SFX_POLICE_RADIO_BEDFORD_POINT);
+	SETZONESFX(5, "COM_EAS", SFX_POLICE_RADIO_NEWPORT);
+	SETZONESFX(6, "PARK", SFX_POLICE_RADIO_BELLEVILLE_PARK);
+	SETZONESFX(7, "UNIVERS", SFX_POLICE_RADIO_LIBERTY_CAMPUS);
+	SETZONESFX(8, "BIG_DAM", SFX_POLICE_RADIO_COCHRANE_DAM);
+	SETZONESFX(9, "SUB_IND", SFX_POLICE_RADIO_PIKE_CREEK);
+	SETZONESFX(10, "SWANKS", SFX_POLICE_RADIO_CEDAR_GROVE);
+	SETZONESFX(11, "PROJECT", SFX_POLICE_RADIO_WICHITA_GARDENS);
+	SETZONESFX(12, "AIRPORT", SFX_POLICE_RADIO_FRANCIS_INTERNATIONAL_AIRPORT);
+	SETZONESFX(13, "PORT_W", SFX_POLICE_RADIO_CALLAHAN_POINT);
+	SETZONESFX(14, "PORT_S", SFX_POLICE_RADIO_ATLANTIC_QUAYS);
+	SETZONESFX(15, "PORT_E", SFX_POLICE_RADIO_PORTLAND_HARBOUR);
+	SETZONESFX(16, "PORT_I", SFX_POLICE_RADIO_TRENTON);
+	SETZONESFX(17, "CHINA", SFX_POLICE_RADIO_CHINATOWN);
+	SETZONESFX(18, "REDLIGH", SFX_POLICE_RADIO_RED_LIGHT_DISTRICT);
+	SETZONESFX(19, "TOWERS", SFX_POLICE_RADIO_HEPBURN_HEIGHTS);
+	SETZONESFX(20, "LITTLEI", SFX_POLICE_RADIO_SAINT_MARKS);
+	SETZONESFX(21, "HARWOOD", SFX_POLICE_RADIO_HARWOOD);
+	SETZONESFX(22, "EASTBAY", SFX_POLICE_RADIO_PORTLAND_BEACH);
+	SETZONESFX(23, "S_VIEW", SFX_POLICE_RADIO_PORTLAND_STRAIGHTS);
+	SETZONESFX(24, "CITYZON", SFX_POLICE_RADIO_LIBERTY_CITY);
+	SETZONESFX(25, "IND_ZON", SFX_POLICE_RADIO_PORTLAND);
+	SETZONESFX(26, "COM_ZON", SFX_POLICE_RADIO_STAUNTON_ISLAND);
+	SETZONESFX(27, "SUB_ZON", SFX_POLICE_RADIO_SHORESIDE_VALE);
+	SETZONESFX(28, "SUB_ZO2", SFX_POLICE_RADIO_SHORESIDE_VALE);
+	SETZONESFX(29, "SUB_ZO3", SFX_POLICE_RADIO_SHORESIDE_VALE);
+	SETZONESFX(30, "A", SFX_POLICE_RADIO_ROCKFORD);
+	SETZONESFX(31, "A", SFX_POLICE_RADIO_ROCKFORD);
+	SETZONESFX(32, "A", SFX_POLICE_RADIO_ROCKFORD);
+	SETZONESFX(33, "A", SFX_POLICE_RADIO_ROCKFORD);
+	SETZONESFX(34, "A", SFX_POLICE_RADIO_ROCKFORD);
+
+#undef SETZONESFX
+
+	strcpy(SubZo2Label, "SUB_ZO2");
+	strcpy(SubZo3Label, "SUB_ZO3");
+}
+
+void
+cAudioManager::InitialisePoliceRadio()
+{
+	m_sPoliceRadioQueue.policeChannelTimer = 0;
+	m_sPoliceRadioQueue.policeChannelTimerSeconds = 0;
+	m_sPoliceRadioQueue.policeChannelCounterSeconds = 0;
+	for (int32 i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++)
+		m_sPoliceRadioQueue.crimes[i].type = 0;
+
+	SampleManager.SetChannelReverbFlag(policeChannel, 0);
+	gSpecialSuspectLastSeenReport = false;
+	for (int32 i = 0; i < ARRAY_SIZE(gMinTimeToNextReport); i++)
+		gMinTimeToNextReport[i] = m_FrameCounter;
+}
+
+void
+cAudioManager::ResetPoliceRadio()
+{
+	if (!m_bIsInitialised) return;
+	if (SampleManager.GetChannelUsedFlag(policeChannel)) SampleManager.StopChannel(policeChannel);
+	InitialisePoliceRadio();
+}
+
+void
+cAudioManager::SetMissionScriptPoliceAudio(int32 sfx) const
+{
+	if (!m_bIsInitialised) return;
+	if (g_nMissionAudioPlayingStatus != 1) {
+		g_nMissionAudioPlayingStatus = 0;
+		g_nMissionAudioSfx = sfx;
+	}
+}
+
+int8
+cAudioManager::GetMissionScriptPoliceAudioPlayingStatus() const
+{
+	return g_nMissionAudioPlayingStatus;
+}
+
+void
+cAudioManager::DoPoliceRadioCrackle()
+{
+	m_sQueueSample.m_nEntityIndex = m_nPoliceChannelEntity;
+	m_sQueueSample.m_nCounter = 0;
+	m_sQueueSample.m_nSampleIndex = SFX_POLICE_RADIO_CRACKLE;
+	m_sQueueSample.m_bBankIndex = SAMPLEBANK_MAIN;
+	m_sQueueSample.m_bIs2D = true;
+	m_sQueueSample.m_nReleasingVolumeModificator = 10;
+	m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_POLICE_RADIO_CRACKLE);
+	m_sQueueSample.m_bVolume = m_anRandomTable[2] % 20 + 15;
+	m_sQueueSample.m_nLoopCount = 0;
+	m_sQueueSample.m_bEmittingVolume = m_sQueueSample.m_bVolume;
+	m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(SFX_POLICE_RADIO_CRACKLE);
+	m_sQueueSample.m_nLoopEnd = SampleManager.GetSampleLoopEndOffset(SFX_POLICE_RADIO_CRACKLE);
+	m_sQueueSample.m_bReleasingSoundFlag = false;
+	m_sQueueSample.m_bReverbFlag = false;
+	m_sQueueSample.m_bOffset = 63;
+	m_sQueueSample.m_nReleasingVolumeDivider = 3;
+	m_sQueueSample.m_bRequireReflection = false;
+	AddSampleToRequestedQueue();
+}
+
+void
+cAudioManager::ServicePoliceRadio()
+{
+	int32 wantedLevel = 0; // uninitialized variable
+	static uint32 nLastSeen = 300;
+
+	if(!m_bIsInitialised) return;
+
+	if(!m_bUserPause) {
+		bool crimeReport = SetupCrimeReport();
+#ifdef FIX_BUGS // Crash at 0x5fe6ef
+		if(!FindPlayerPed() || !FindPlayerPed()->m_pWanted) return;
+#endif
+		wantedLevel = FindPlayerPed()->m_pWanted->m_nWantedLevel;
+		if(!crimeReport) {
+			if(wantedLevel) {
+				if(nLastSeen) {
+					--nLastSeen;
+				} else {
+					nLastSeen = m_anRandomTable[1] % 1000 + 2000;
+					SetupSuspectLastSeenReport();
+				}
+			}
+		}
+	}
+	ServicePoliceRadioChannel(wantedLevel);
+}
+
+void
+cAudioManager::ServicePoliceRadioChannel(int32 wantedLevel)
+{
+	bool processed = false;
+	uint32 sample;
+	int32 freq;
+
+	static int cWait = 0;
+	static bool bChannelOpen = false;
+	static uint8 bMissionAudioPhysicalPlayingStatus = 0;
+	static int32 PoliceChannelFreq = 5500;
+
+	if (!m_bIsInitialised) return;
+
+	if (m_bUserPause) {
+		if (SampleManager.GetChannelUsedFlag(policeChannel)) SampleManager.StopChannel(policeChannel);
+		if (g_nMissionAudioSfx != TOTAL_AUDIO_SAMPLES && bMissionAudioPhysicalPlayingStatus == 1 &&
+			SampleManager.IsStreamPlaying(1)) {
+			SampleManager.PauseStream(1, 1);
+		}
+	} else {
+		if (m_bPreviousUserPause && g_nMissionAudioSfx != TOTAL_AUDIO_SAMPLES &&
+			bMissionAudioPhysicalPlayingStatus == 1) {
+			SampleManager.PauseStream(0, 1);
+		}
+		if (m_sPoliceRadioQueue.policeChannelTimer == 0) bChannelOpen = false;
+		if (cWait) {
+			--cWait;
+			return;
+		}
+		if (g_nMissionAudioSfx != TOTAL_AUDIO_SAMPLES && !bChannelOpen) {
+			if (g_nMissionAudioPlayingStatus) {
+				if (g_nMissionAudioPlayingStatus == 1 && !bMissionAudioPhysicalPlayingStatus &&
+					SampleManager.IsStreamPlaying(1)) {
+					bMissionAudioPhysicalPlayingStatus = 1;
+				}
+				if (bMissionAudioPhysicalPlayingStatus == 1) {
+					if (SampleManager.IsStreamPlaying(1)) {
+						DoPoliceRadioCrackle();
+					} else {
+						bMissionAudioPhysicalPlayingStatus = 2;
+						g_nMissionAudioPlayingStatus = 2;
+						g_nMissionAudioSfx = TOTAL_AUDIO_SAMPLES;
+						cWait = 30;
+					}
+					return;
+				}
+			} else if (!SampleManager.GetChannelUsedFlag(policeChannel)) {
+				SampleManager.PreloadStreamedFile(g_nMissionAudioSfx, 1);
+				SampleManager.SetStreamedVolumeAndPan(maxVolume, 63, 1, 1);
+				SampleManager.StartPreloadedStreamedFile(1);
+				g_nMissionAudioPlayingStatus = 1;
+				bMissionAudioPhysicalPlayingStatus = 0;
+				return;
+			}
+		}
+		if (bChannelOpen) DoPoliceRadioCrackle();
+		if ((g_nMissionAudioSfx == TOTAL_AUDIO_SAMPLES || g_nMissionAudioPlayingStatus != 1) &&
+			!SampleManager.GetChannelUsedFlag(policeChannel) && m_sPoliceRadioQueue.policeChannelTimer) {
+			if (m_sPoliceRadioQueue.policeChannelTimer) {
+				sample = m_sPoliceRadioQueue.crimesSamples[m_sPoliceRadioQueue.policeChannelCounterSeconds];
+				m_sPoliceRadioQueue.policeChannelTimer--;
+				m_sPoliceRadioQueue.policeChannelCounterSeconds = (m_sPoliceRadioQueue.policeChannelCounterSeconds + 1) % 60;
+			} else {
+				sample = TOTAL_AUDIO_SAMPLES;
+			}
+			if (!wantedLevel) {
+				if (gSpecialSuspectLastSeenReport) {
+					gSpecialSuspectLastSeenReport = 0;
+				} else if (((sample >= SFX_POLICE_RADIO_MESSAGE_NOISE_1) && (sample <= SFX_POLICE_RADIO_MESSAGE_NOISE_3)) || sample == TOTAL_AUDIO_SAMPLES) {
+					bChannelOpen = false;
+					processed = true;
+				}
+			}
+			if (sample == TOTAL_AUDIO_SAMPLES) {
+				if (!processed) cWait = 30;
+			} else {
+				SampleManager.InitialiseChannel(policeChannel, sample, 0);
+				switch (sample) {
+				case SFX_POLICE_RADIO_MESSAGE_NOISE_1:
+				case SFX_POLICE_RADIO_MESSAGE_NOISE_2:
+				case SFX_POLICE_RADIO_MESSAGE_NOISE_3:
+					freq = m_anRandomTable[4] % 2000 + 10025;
+					bChannelOpen = bChannelOpen == false;
+					break;
+				default: freq = SampleManager.GetSampleBaseFrequency(sample); break;
+				}
+				PoliceChannelFreq = freq;
+				SampleManager.SetChannelFrequency(policeChannel, freq);
+				SampleManager.SetChannelVolume(policeChannel, 100);
+				SampleManager.SetChannelPan(policeChannel, 63);
+				SampleManager.SetChannelLoopCount(policeChannel, 1);
+				SampleManager.SetChannelLoopPoints(policeChannel, 0, -1);
+				SampleManager.StartChannel(policeChannel);
+			}
+			if (processed) ResetPoliceRadio();
+		}
+	}
+}
+
+bool
+cAudioManager::SetupCrimeReport()
+{
+	int16 audioZoneId;
+	CZone *zone;
+	float rangeX;
+	float rangeY;
+	float halfX;
+	float halfY;
+	float quarterX;
+	float quarterY;
+	int i;
+	int32 sampleIndex;
+	bool processed = false;
+
+	if (MusicManager.m_nMusicMode == MUSICMODE_CUTSCENE) return false;
+
+	if (60 - m_sPoliceRadioQueue.policeChannelTimer <= 9) {
+		AgeCrimes();
+		return true;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++) {
+		if (m_sPoliceRadioQueue.crimes[i].type != CRIME_NONE)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(m_sPoliceRadioQueue.crimes)) return false;
+	audioZoneId = CTheZones::FindAudioZone(&m_sPoliceRadioQueue.crimes[i].position);
+	if (audioZoneId >= 0 && audioZoneId < NUMAUDIOZONES) {
+		zone = &CTheZones::ZoneArray[CTheZones::AudioZoneArray[audioZoneId]];
+		for (int j = 0; j < NUMAUDIOZONES; j++) {
+			if (strcmp(zone->name, ZoneSfx[j].m_aName) == 0) {
+				sampleIndex = ZoneSfx[j].m_nSampleIndex;
+				m_sPoliceRadioQueue.Add(m_anRandomTable[4] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+				m_sPoliceRadioQueue.Add(m_anRandomTable[0] % 3 + SFX_WEVE_GOT);
+				m_sPoliceRadioQueue.Add(m_anRandomTable[1] % 2 + SFX_A_10_1);
+				switch (m_sPoliceRadioQueue.crimes[i].type) {
+				case CRIME_PED_BURNED: m_sPoliceRadioQueue.crimes[i].type = CRIME_HIT_PED; break;
+				case CRIME_COP_BURNED: m_sPoliceRadioQueue.crimes[i].type = CRIME_HIT_COP; break;
+				case CRIME_VEHICLE_BURNED: m_sPoliceRadioQueue.crimes[i].type = CRIME_STEAL_CAR; break;
+				case CRIME_DESTROYED_CESSNA: m_sPoliceRadioQueue.crimes[i].type = CRIME_SHOOT_HELI; break;
+				default: break;
+				}
+				m_sPoliceRadioQueue.Add(m_sPoliceRadioQueue.crimes[i].type + SFX_CRIME_1 - 1);
+				m_sPoliceRadioQueue.Add(SFX_IN);
+				if (sampleIndex == SFX_POLICE_RADIO_SHORESIDE_VALE &&
+					(strcmp(zone->name, SubZo2Label) == 0 || strcmp(zone->name, SubZo3Label) == 0)) {
+					m_sPoliceRadioQueue.Add(SFX_NORTH);
+					m_sPoliceRadioQueue.Add(SFX_EAST);
+				} else {
+					rangeX = zone->maxx - zone->minx;
+					rangeY = zone->maxy - zone->miny;
+					halfX = 0.5f * rangeX + zone->minx;
+					halfY = 0.5f * rangeY + zone->miny;
+					quarterX = 0.25f * rangeX;
+					quarterY = 0.25f * rangeY;
+
+					if (m_sPoliceRadioQueue.crimes[i].position.y > halfY + quarterY) {
+						m_sPoliceRadioQueue.Add(SFX_NORTH);
+						processed = true;
+					} else if (m_sPoliceRadioQueue.crimes[i].position.y < halfY - quarterY) {
+						m_sPoliceRadioQueue.Add(SFX_SOUTH);
+						processed = true;
+					}
+
+					if (m_sPoliceRadioQueue.crimes[i].position.x > halfX + quarterX)
+						m_sPoliceRadioQueue.Add(SFX_EAST);
+					else if (m_sPoliceRadioQueue.crimes[i].position.x < halfX - quarterX)
+						m_sPoliceRadioQueue.Add(SFX_WEST);
+					else if (!processed)
+						m_sPoliceRadioQueue.Add(SFX_CENTRAL);
+
+					m_sPoliceRadioQueue.Add(sampleIndex);
+					m_sPoliceRadioQueue.Add(m_anRandomTable[2] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+					m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
+				}
+				break;
+			}
+		}
+	}
+	m_sPoliceRadioQueue.crimes[i].type = CRIME_NONE;
+	AgeCrimes();
+	return true;
+}
+
+void
+cAudioManager::SetupSuspectLastSeenReport()
+{
+	CVehicle *veh;
+	uint8 color1;
+	int32 main_color;
+	int32 sample;
+
+	int32 color_pre_modifier;
+	int32 color_post_modifier;
+
+	const int32 gCarColourTable[][3] = {
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLACK, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_WHITE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_BRIGHT, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_BLUE, SFX_POLICE_RADIO_GREY},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+#else
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+#endif
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_RED, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+#else
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+#endif
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_ORANGE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+#else
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+#endif
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_YELLOW, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+#else
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+#endif
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_GREEN, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+#else
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+#endif
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_BLUE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_PURPLE, SFX_POLICE_RADIO_BLUE},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+#else
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+#endif
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, SFX_POLICE_RADIO_GREY},
+#else
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+#endif
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_PURPLE, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+#else
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+#endif
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+#ifdef FIX_BUGS
+		{SFX_POLICE_RADIO_LIGHT, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+#else
+		{TOTAL_AUDIO_SAMPLES, SFX_POLICE_RADIO_SILVER, TOTAL_AUDIO_SAMPLES},
+#endif
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_LIGHT, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES},
+		{SFX_POLICE_RADIO_DARK, TOTAL_AUDIO_SAMPLES, TOTAL_AUDIO_SAMPLES}
+	};
+
+	if (MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE) {
+		veh = FindPlayerVehicle();
+		if (veh != nil) {
+			if (60 - m_sPoliceRadioQueue.policeChannelTimer > 9) {
+				color1 = veh->m_currentColour1;
+				if (color1 >= ARRAY_SIZE(gCarColourTable)) {
+					debug("\n *** UNKNOWN CAR COLOUR %d *** ", color1);
+				} else {
+					main_color = gCarColourTable[color1][1];
+					color_pre_modifier = gCarColourTable[color1][0];
+					color_post_modifier = gCarColourTable[color1][2];
+					switch (veh->m_modelIndex) {
+#ifdef FIX_BUGS
+					case MI_COLUMB:
+						main_color = SFX_POLICE_RADIO_BLUE;
+						color_pre_modifier = color_post_modifier = TOTAL_AUDIO_SAMPLES;
+#endif
+					case MI_LANDSTAL:
+					case MI_BLISTA: sample = SFX_POLICE_RADIO_CRUISER; break;
+#ifdef FIX_BUGS
+					case MI_YARDIE:
+						color_pre_modifier = TOTAL_AUDIO_SAMPLES;
+						main_color = SFX_POLICE_RADIO_RED;
+						color_post_modifier = SFX_POLICE_RADIO_YELLOW;
+						sample = SFX_POLICE_RADIO_CONVERTIBLE; break;
+					case MI_DIABLOS:
+						main_color = SFX_POLICE_RADIO_BLACK;
+#endif
+					case MI_IDAHO:
+					case MI_STALLION: sample = SFX_POLICE_RADIO_CONVERTIBLE; break;
+#ifdef FIX_BUGS
+					case MI_YAKUZA:
+						color_pre_modifier = TOTAL_AUDIO_SAMPLES;
+						main_color = SFX_POLICE_RADIO_SILVER;
+						color_post_modifier = SFX_POLICE_RADIO_RED;
+#endif
+					case MI_STINGER:
+					case MI_INFERNUS:
+					case MI_CHEETAH:
+					case MI_BANSHEE: sample = SFX_POLICE_RADIO_SPORTS_CAR; break;
+#ifdef FIX_BUGS
+					case MI_MAFIA:
+						color_pre_modifier = color_post_modifier = TOTAL_AUDIO_SAMPLES;
+						main_color = SFX_POLICE_RADIO_GREY;
+					case MI_KURUMA:
+#endif
+					case MI_PEREN:
+					case MI_SENTINEL:
+					case MI_FBICAR: sample = SFX_POLICE_RADIO_SALOON; break;
+					case MI_PATRIOT:
+					case MI_BOBCAT: sample = SFX_POLICE_RADIO_PICKUP; break;
+					case MI_FIRETRUCK: sample = SFX_POLICE_RADIO_FIRE_TRUCK; break;
+#ifdef FIX_BUGS
+					case MI_LINERUN:
+					case MI_FLATBED:
+#endif
+					case MI_TRASH:
+					case MI_BARRACKS: sample = SFX_POLICE_RADIO_TRUCK; break;
+					case MI_STRETCH: sample = SFX_POLICE_RADIO_LIMO; break;
+#ifdef FIX_BUGS
+					case MI_CORPSE:
+#endif
+					case MI_MANANA:
+					case MI_ESPERANT: sample = SFX_POLICE_RADIO_2_DOOR; break;
+#ifdef FIX_BUGS
+					case MI_HOODS:
+						color_pre_modifier = TOTAL_AUDIO_SAMPLES;
+						main_color = SFX_POLICE_RADIO_BLUE;
+						color_post_modifier = SFX_POLICE_RADIO_GREEN;
+					case MI_BELLYUP:
+					case MI_YANKEE:
+					case MI_TOYZ:
+					case MI_MRWONGS:
+					case MI_PANLANT:
+#endif
+					case MI_PONY:
+					case MI_MULE:
+					case MI_MOONBEAM:
+					case MI_ENFORCER:
+					case MI_SECURICA:
+					case MI_RUMPO: sample = SFX_POLICE_RADIO_VAN; break;
+					case MI_AMBULAN: sample = SFX_POLICE_RADIO_AMBULANCE; break;
+					case MI_TAXI:
+					case MI_CABBIE:
+					case MI_BORGNINE: sample = SFX_POLICE_RADIO_TAXI; break;
+					case MI_MRWHOOP:
+						sample = SFX_POLICE_RADIO_ICE_CREAM_VAN;
+						break;
+					case MI_BFINJECT: sample = SFX_POLICE_RADIO_BUGGY; break;
+					case MI_POLICE: sample = SFX_POLICE_RADIO_POLICE_CAR; break;
+#ifdef FIX_BUGS
+					case MI_SPEEDER:
+					case MI_REEFER:
+					case MI_GHOST:
+#endif
+					case MI_PREDATOR: sample = SFX_POLICE_RADIO_BOAT; break;
+					case MI_BUS:
+					case MI_COACH: sample = SFX_POLICE_RADIO_BUS; break;
+					case MI_RHINO:
+						sample = SFX_POLICE_RADIO_TANK;
+						main_color = TOTAL_AUDIO_SAMPLES;
+						color_post_modifier = TOTAL_AUDIO_SAMPLES;
+						break;
+					case MI_TRAIN:
+						sample = SFX_POLICE_RADIO_SUBWAY_CAR;
+						main_color = TOTAL_AUDIO_SAMPLES;
+						color_post_modifier = TOTAL_AUDIO_SAMPLES;
+
+						break;
+					default:
+						debug("\n *** UNKNOWN CAR MODEL INDEX %d *** ", veh->m_modelIndex);
+						return;
+					}
+					m_sPoliceRadioQueue.Add(m_anRandomTable[4] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+					m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_SUSPECT);
+					if (m_anRandomTable[3] % 2) 
+						m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_LAST_SEEN);
+#ifdef FIX_BUGS
+					if (main_color == SFX_POLICE_RADIO_ORANGE && color_pre_modifier == TOTAL_AUDIO_SAMPLES)
+#else
+					if (main_color == SFX_POLICE_RADIO_ORANGE)
+#endif
+						m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_IN_AN);
+					else
+						m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_IN_A);
+					if (color_pre_modifier != TOTAL_AUDIO_SAMPLES)
+						m_sPoliceRadioQueue.Add(color_pre_modifier);
+					if (main_color != TOTAL_AUDIO_SAMPLES)
+						m_sPoliceRadioQueue.Add(main_color);
+					if (color_post_modifier != TOTAL_AUDIO_SAMPLES)
+						m_sPoliceRadioQueue.Add(color_post_modifier);
+					m_sPoliceRadioQueue.Add(sample);
+					m_sPoliceRadioQueue.Add(m_anRandomTable[0] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+					m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
+				}
+			}
+		} else if (60 - m_sPoliceRadioQueue.policeChannelTimer > 4) {
+			m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+			m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_SUSPECT);
+			m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_ON_FOOT);
+			m_sPoliceRadioQueue.Add(m_anRandomTable[0] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+			m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
+		}
+	}
+}
+
+
+
+void
+cAudioManager::ReportCrime(int32 type, const CVector *pos)
+{
+	int32 lastCrime = ARRAY_SIZE(m_sPoliceRadioQueue.crimes);
+	if (m_bIsInitialised && MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 &&
+		(type > CRIME_NONE || type < NUM_CRIME_TYPES) && m_FrameCounter >= gMinTimeToNextReport[type]) {
+		for (int32 i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++) {
+			if (m_sPoliceRadioQueue.crimes[i].type) {
+				if (m_sPoliceRadioQueue.crimes[i].type == type) {
+					m_sPoliceRadioQueue.crimes[i].position = *pos;
+					m_sPoliceRadioQueue.crimes[i].timer = 0;
+					return;
+				}
+			} else {
+				lastCrime = i;
+			}
+		}
+
+		if (lastCrime < ARRAY_SIZE(m_sPoliceRadioQueue.crimes)) {
+			m_sPoliceRadioQueue.crimes[lastCrime].type = type;
+			m_sPoliceRadioQueue.crimes[lastCrime].position = *pos;
+			m_sPoliceRadioQueue.crimes[lastCrime].timer = 0;
+			gMinTimeToNextReport[type] = m_FrameCounter + 500;
+		}
+	}
+}
+
+void
+cAudioManager::PlaySuspectLastSeen(float x, float y, float z)
+{
+	int16 audioZone;
+	CZone *zone;
+	float rangeX;
+	float rangeY;
+	float halfX;
+	float halfY;
+	float quarterX;
+	float quarterY;
+	int32 sample;
+	bool processed = false;
+	CVector vec = CVector(x, y, z);
+
+	if (!m_bIsInitialised) return;
+
+	if (MusicManager.m_nMusicMode != MUSICMODE_CUTSCENE && 60 - m_sPoliceRadioQueue.policeChannelTimer > 9) {
+		audioZone = CTheZones::FindAudioZone(&vec);
+		if (audioZone >= 0 && audioZone < NUMAUDIOZONES) {
+			zone = &CTheZones::ZoneArray[CTheZones::AudioZoneArray[audioZone]];
+			for (int i = 0; i < NUMAUDIOZONES; i++) {
+				if (strcmp(zone->name, ZoneSfx[i].m_aName) == 0) {
+					sample = ZoneSfx[i].m_nSampleIndex;
+					m_sPoliceRadioQueue.Add(m_anRandomTable[4] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+					m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_SUSPECT);
+					m_sPoliceRadioQueue.Add(SFX_POLICE_RADIO_LAST_SEEN);
+					m_sPoliceRadioQueue.Add(SFX_IN);
+					if (sample == SFX_POLICE_RADIO_SHORESIDE_VALE &&
+						(strcmp(zone->name, SubZo2Label) == 0 ||
+							strcmp(zone->name, SubZo3Label) == 0)) {
+						m_sPoliceRadioQueue.Add(SFX_NORTH);
+						m_sPoliceRadioQueue.Add(SFX_EAST);
+					} else {
+						rangeX = zone->maxx - zone->minx;
+						rangeY = zone->maxy - zone->miny;
+						halfX = 0.5f * rangeX + zone->minx;
+						halfY = 0.5f * rangeY + zone->miny;
+						quarterX = 0.25f * rangeX;
+						quarterY = 0.25f * rangeY;
+
+						if (vec.y > halfY + quarterY) {
+							m_sPoliceRadioQueue.Add(SFX_NORTH);
+							processed = true;
+						} else if (vec.y < halfY - quarterY) {
+							m_sPoliceRadioQueue.Add(SFX_SOUTH);
+							processed = true;
+						}
+
+						if (vec.x > halfX + quarterX)
+							m_sPoliceRadioQueue.Add(SFX_EAST);
+						else if (vec.x < halfX - quarterX)
+							m_sPoliceRadioQueue.Add(SFX_WEST);
+						else if (!processed)
+							m_sPoliceRadioQueue.Add(SFX_CENTRAL);
+					}
+					m_sPoliceRadioQueue.Add(sample);
+					m_sPoliceRadioQueue.Add(m_anRandomTable[2] % 3 + SFX_POLICE_RADIO_MESSAGE_NOISE_1);
+					m_sPoliceRadioQueue.Add(TOTAL_AUDIO_SAMPLES);
+					gSpecialSuspectLastSeenReport = true;
+					break;
+				}
+			}
+		}
+	}
+}
+
+void
+cAudioManager::AgeCrimes()
+{
+	for (uint8 i = 0; i < ARRAY_SIZE(m_sPoliceRadioQueue.crimes); i++) {
+		if (m_sPoliceRadioQueue.crimes[i].type != CRIME_NONE) {
+			if (++m_sPoliceRadioQueue.crimes[i].timer > 1500) m_sPoliceRadioQueue.crimes[i].type = CRIME_NONE;
+		}
+	}
+}
+
+STARTPATCHES
+InjectHook(0x580AF0, &cAudioManager::AgeCrimes, PATCH_JUMP);
+InjectHook(0x57F060, &cAudioManager::DoPoliceRadioCrackle, PATCH_JUMP);
+InjectHook(0x57F050, &cAudioManager::GetMissionScriptPoliceAudioPlayingStatus, PATCH_JUMP);
+InjectHook(0x57EEC0, &cAudioManager::InitialisePoliceRadio, PATCH_JUMP);
+InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP);
+InjectHook(0x580500, &cAudioManager::PlaySuspectLastSeen, PATCH_JUMP);
+InjectHook(0x5803D0, &cAudioManager::ReportCrime, PATCH_JUMP);
+InjectHook(0x57EFF0, &cAudioManager::ResetPoliceRadio, PATCH_JUMP);
+InjectHook(0x57F110, &cAudioManager::ServicePoliceRadio, PATCH_JUMP);
+InjectHook(0x57F1B0, &cAudioManager::ServicePoliceRadioChannel, PATCH_JUMP);
+InjectHook(0x57F020, &cAudioManager::SetMissionScriptPoliceAudio, PATCH_JUMP);
+InjectHook(0x57F5B0, &cAudioManager::SetupCrimeReport, PATCH_JUMP);
+InjectHook(0x57FCC0, &cAudioManager::SetupSuspectLastSeenReport, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/audio/PoliceRadio.h b/src/audio/PoliceRadio.h
index 4c7030f1..0f351f52 100644
--- a/src/audio/PoliceRadio.h
+++ b/src/audio/PoliceRadio.h
@@ -1,46 +1,46 @@
-#pragma once
-
-#include "Wanted.h"
-
-struct cAMCrime {
-	int32 type;
-	CVector position;
-	uint16 timer;
-
-	cAMCrime()
-	{
-		type = CRIME_NONE;
-		position = CVector(0.0f, 0.0f, 0.0f);
-		timer = 0;
-	}
-};
-
-static_assert(sizeof(cAMCrime) == 20, "cAMCrime: error ");
-
-class cPoliceRadioQueue
-{
-public:
-	int32 crimesSamples[60];
-	uint8 policeChannelTimer;
-	uint8 policeChannelTimerSeconds;
-	uint8 policeChannelCounterSeconds;
-	cAMCrime crimes[10];
-
-	cPoliceRadioQueue()
-	{
-		policeChannelTimerSeconds = 0;
-		policeChannelCounterSeconds = 0;
-		policeChannelTimer = 0;
-	}
-
-	void Add(uint32 sample)
-	{
-		if (policeChannelTimer != 60) {
-			crimesSamples[policeChannelTimerSeconds] = sample;
-			policeChannelTimer++;
-			policeChannelTimerSeconds = (policeChannelTimerSeconds + 1) % 60;
-		}
-	}
-};
-
+#pragma once
+
+#include "Wanted.h"
+
+struct cAMCrime {
+	int32 type;
+	CVector position;
+	uint16 timer;
+
+	cAMCrime()
+	{
+		type = CRIME_NONE;
+		position = CVector(0.0f, 0.0f, 0.0f);
+		timer = 0;
+	}
+};
+
+static_assert(sizeof(cAMCrime) == 20, "cAMCrime: error ");
+
+class cPoliceRadioQueue
+{
+public:
+	int32 crimesSamples[60];
+	uint8 policeChannelTimer;
+	uint8 policeChannelTimerSeconds;
+	uint8 policeChannelCounterSeconds;
+	cAMCrime crimes[10];
+
+	cPoliceRadioQueue()
+	{
+		policeChannelTimerSeconds = 0;
+		policeChannelCounterSeconds = 0;
+		policeChannelTimer = 0;
+	}
+
+	void Add(uint32 sample)
+	{
+		if (policeChannelTimer != 60) {
+			crimesSamples[policeChannelTimerSeconds] = sample;
+			policeChannelTimer++;
+			policeChannelTimerSeconds = (policeChannelTimerSeconds + 1) % 60;
+		}
+	}
+};
+
 static_assert(sizeof(cPoliceRadioQueue) == 444, "cPoliceRadioQueue: error ");
\ No newline at end of file
diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp
index 70099291..b5bca21d 100644
--- a/src/control/AutoPilot.cpp
+++ b/src/control/AutoPilot.cpp
@@ -12,17 +12,17 @@ void CAutoPilot::ModifySpeed(float speed)
 	float positionBetweenNodes = (float)(CTimer::GetTimeInMilliseconds() - m_nTimeEnteredCurve) / m_nTimeToSpendOnCurrentCurve;
 	CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo];
 	CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[m_nNextPathNodeInfo];
-	float currentPathLinkForwardX = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dirX;
-	float currentPathLinkForwardY = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dirY;
-	float nextPathLinkForwardX = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dirX;
-	float nextPathLinkForwardY = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dirY;
+	float currentPathLinkForwardX = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dir.x;
+	float currentPathLinkForwardY = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].dir.y;
+	float nextPathLinkForwardX = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dir.x;
+	float nextPathLinkForwardY = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].dir.y;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurrentLink->posX + ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardY,
-		pCurrentLink->posY - ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardX,
+		pCurrentLink->pos.x + ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurrentLink->pos.y - ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardY,
-		pNextLink->posY - ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardX,
+		pNextLink->pos.x + ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->pos.y - ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
 	m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
 		&positionOnCurrentLinkIncludingLane,
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 3174a253..264f1f3f 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -90,7 +90,7 @@ uint32 (&aCarsToKeepTime)[MAX_CARS_TO_KEEP] = *(uint32(*)[MAX_CARS_TO_KEEP])*(ui
 void
 CCarCtrl::GenerateRandomCars()
 {
-	if (CCutsceneMgr::IsCutsceneProcessing())
+	if (CCutsceneMgr::IsRunning())
 		return;
 	if (NumRandomCars < 30){
 		if (CountDownToCarsAtStart == 0){
@@ -393,25 +393,25 @@ CCarCtrl::GenerateOneRandomCar()
 	pCar->GetRight() = CVector(forwardY, -forwardX, 0.0f);
 	pCar->GetUp() = CVector(0.0f, 0.0f, 1.0f);
 
-	float currentPathLinkForwardX = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dirX;
-	float currentPathLinkForwardY = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dirY;
-	float nextPathLinkForwardX = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dirX;
-	float nextPathLinkForwardY = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dirY;
+	float currentPathLinkForwardX = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dir.x;
+	float currentPathLinkForwardY = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].dir.y;
+	float nextPathLinkForwardX = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dir.x;
+	float nextPathLinkForwardY = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dir.y;
 
 	CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo];
 	CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo];
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurrentLink->posX + ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
-		pCurrentLink->posY - ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+		pCurrentLink->pos.x + ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurrentLink->pos.y - ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
-		pNextLink->posY - ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+		pNextLink->pos.x + ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->pos.y - ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
-	float directionCurrentLinkX = pCurrentLink->dirX * pCar->AutoPilot.m_nCurrentDirection;
-	float directionCurrentLinkY = pCurrentLink->dirY * pCar->AutoPilot.m_nCurrentDirection;
-	float directionNextLinkX = pNextLink->dirX * pCar->AutoPilot.m_nNextDirection;
-	float directionNextLinkY = pNextLink->dirY * pCar->AutoPilot.m_nNextDirection;
+	float directionCurrentLinkX = pCurrentLink->dir.x * pCar->AutoPilot.m_nCurrentDirection;
+	float directionCurrentLinkY = pCurrentLink->dir.y * pCar->AutoPilot.m_nCurrentDirection;
+	float directionNextLinkX = pNextLink->dir.x * pCar->AutoPilot.m_nNextDirection;
+	float directionNextLinkY = pNextLink->dir.y * pCar->AutoPilot.m_nNextDirection;
 	/* We want to make a path between two links that may not have the same forward directions a curve. */
 	pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
 		&positionOnCurrentLinkIncludingLane,
@@ -763,17 +763,17 @@ CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
 		return;
 	CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
 	CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
-	float currentPathLinkForwardX = pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
-	float currentPathLinkForwardY = pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
-	float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
-	float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+	float currentPathLinkForwardX = pCurrentLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+	float currentPathLinkForwardY = pCurrentLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+	float nextPathLinkForwardX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+	float nextPathLinkForwardY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
-		pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+		pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
-		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+		pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
 	CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f);
 	CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f);
@@ -1553,8 +1553,8 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
 		pVehicle->AutoPilot.m_nNextDirection = -1;
 		lanesOnNextNode = pNextLink->numRightLanes;
 	}
-	float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirX;
-	float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirX;
+	float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.x;
+	float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.x;
 	if (lanesOnNextNode >= 0){
 		if ((CGeneral::GetRandomNumber() & 0x600) == 0){
 			/* 25% chance vehicle will try to switch lane */
@@ -1574,17 +1574,17 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
 	if (pVehicle->AutoPilot.m_bStayInFastLane)
 		pVehicle->AutoPilot.m_nNextLane = 0;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), /* ...what about Y? */
-		pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+		pCurLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), /* ...what about Y? */
+		pCurLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH),
-		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+		pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH),
+		pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
-	float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
-	float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
-	float directionNextLinkX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
-	float directionNextLinkY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+	float directionCurrentLinkX = pCurLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+	float directionCurrentLinkY = pCurLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+	float directionNextLinkX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+	float directionNextLinkY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
 	/* We want to make a path between two links that may not have the same forward directions a curve. */
 	pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
 		&positionOnCurrentLinkIncludingLane,
@@ -1725,10 +1725,10 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t
 		pVehicle->AutoPilot.m_nNextDirection = -1;
 		lanesOnNextNode = pNextLink->numRightLanes;
 	}
-	float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirX;
-	float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirY;
-	float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirX;
-	float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirY;
+	float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.x;
+	float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.y;
+	float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.x;
+	float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.y;
 	if (lanesOnNextNode >= 0) {
 		CVector2D dist = pNextPathNode->pos - pCurNode->pos;
 		if (dist.MagnitudeSqr() >= SQR(7.0f)){
@@ -1755,17 +1755,17 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t
 	if (pVehicle->AutoPilot.m_bStayInFastLane)
 		pVehicle->AutoPilot.m_nNextLane = 0;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
-		pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+		pCurLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
-		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+		pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
-	float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
-	float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
-	float directionNextLinkX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
-	float directionNextLinkY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+	float directionCurrentLinkX = pCurLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+	float directionCurrentLinkY = pCurLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+	float directionNextLinkX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+	float directionNextLinkY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
 	/* We want to make a path between two links that may not have the same forward directions a curve. */
 	pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
 		&positionOnCurrentLinkIncludingLane,
@@ -1814,10 +1814,10 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
 		pVehicle->AutoPilot.m_nNextDirection = -1;
 		lanesOnNextNode = pNextLink->numRightLanes;
 	}
-	float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirX;
-	float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dirY;
-	float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirX;
-	float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dirY;
+	float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.x;
+	float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * pCurLink->dir.y;
+	float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.x;
+	float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * pNextLink->dir.y;
 	if (lanesOnNextNode >= 0) {
 		CVector2D dist = pNextPathNode->pos - pCurNode->pos;
 		if (dist.MagnitudeSqr() >= SQR(7.0f) && (CGeneral::GetRandomNumber() & 0x600) == 0) {
@@ -1835,17 +1835,17 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
 	if (pVehicle->AutoPilot.m_bStayInFastLane)
 		pVehicle->AutoPilot.m_nNextLane = 0;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
-		pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
+		pCurLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
-		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
+		pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
-	float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
-	float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
-	float directionNextLinkX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
-	float directionNextLinkY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+	float directionCurrentLinkX = pCurLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+	float directionCurrentLinkY = pCurLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+	float directionNextLinkX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+	float directionNextLinkY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
 	/* We want to make a path between two links that may not have the same forward directions a curve. */
 	pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
 		&positionOnCurrentLinkIncludingLane,
@@ -2192,16 +2192,16 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv
 	forward.Normalise();
 	CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
 	CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
-	CVector2D currentPathLinkForward(pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection,
-		pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection);
-	float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
-	float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+	CVector2D currentPathLinkForward(pCurrentLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection,
+		pCurrentLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection);
+	float nextPathLinkForwardX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+	float nextPathLinkForwardY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
 	CVector2D positionOnCurrentLinkIncludingLane(
-		pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
-		pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
+		pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
+		pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
 	CVector2D positionOnNextLinkIncludingLane(
-		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
-		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX);
+		pNextLink->pos.x + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->pos.y - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX);
 	CVector2D distanceToNextNode = (CVector2D)pVehicle->GetPosition() - positionOnCurrentLinkIncludingLane;
 	float scalarDistanceToNextNode = distanceToNextNode.Magnitude();
 	CVector2D distanceBetweenNodes = positionOnNextLinkIncludingLane - positionOnCurrentLinkIncludingLane;
@@ -2230,16 +2230,16 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv
 		}
 		pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
 		scalarDistanceToNextNode = CVector2D(
-			pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y - pVehicle->GetPosition().x,
-			pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x - pVehicle->GetPosition().y).Magnitude();		
+			pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y - pVehicle->GetPosition().x,
+			pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x - pVehicle->GetPosition().y).Magnitude();		
 		pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
-		currentPathLinkForward.x = pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
-		currentPathLinkForward.y = pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
-		nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
-		nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+		currentPathLinkForward.x = pCurrentLink->dir.x * pVehicle->AutoPilot.m_nCurrentDirection;
+		currentPathLinkForward.y = pCurrentLink->dir.y * pVehicle->AutoPilot.m_nCurrentDirection;
+		nextPathLinkForwardX = pNextLink->dir.x * pVehicle->AutoPilot.m_nNextDirection;
+		nextPathLinkForwardY = pNextLink->dir.y * pVehicle->AutoPilot.m_nNextDirection;
 	}
-	positionOnCurrentLinkIncludingLane.x = pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y;
-	positionOnCurrentLinkIncludingLane.y = pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x;
+	positionOnCurrentLinkIncludingLane.x = pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y;
+	positionOnCurrentLinkIncludingLane.y = pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x;
 	CVector2D projectedPosition = positionOnCurrentLinkIncludingLane - currentPathLinkForward * scalarDistanceToNextNode * 0.4f;
 	if (scalarDistanceToNextNode > DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN){
 		projectedPosition.x = positionOnCurrentLinkIncludingLane.x;
@@ -2281,8 +2281,8 @@ void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerv
 		CCarAI::CarHasReasonToStop(pVehicle);
 		speedStyleMultiplier = 0.0f;
 	}
-	CVector2D trajectory(pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
-		pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
+	CVector2D trajectory(pCurrentLink->pos.x + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
+		pCurrentLink->pos.y - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
 	trajectory -= pVehicle->GetPosition();
 	float speedAngleMultiplier = FindSpeedMultiplier(
 		CGeneral::GetATanOfXY(trajectory.x, trajectory.y) - angleForward,
diff --git a/src/control/Cranes.cpp b/src/control/Cranes.cpp
deleted file mode 100644
index 4c1bf2c8..00000000
--- a/src/control/Cranes.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "common.h"
-#include "patcher.h"
-#include "Cranes.h"
-
-WRAPPER bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle*) { EAXJMP(0x5451E0); }
-WRAPPER bool CCranes::IsThisCarBeingCarriedByAnyCrane(CVehicle*) { EAXJMP(0x545190); }
-WRAPPER bool CCranes::IsThisCarPickedUp(float, float, CVehicle*) { EAXJMP(0x543940); }
-WRAPPER bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane() { EAXJMP(0x544BE0); }
-WRAPPER void CCranes::ActivateCrane(float, float, float, float, float, float, float, float, bool, bool, float, float) { EAXJMP(0x543650); }
-WRAPPER void CCranes::DeActivateCrane(float, float) { EAXJMP(0x543890); }
-WRAPPER void CCranes::InitCranes(void) { EAXJMP(0x543360); }
-WRAPPER void CCranes::UpdateCranes(void) { EAXJMP(0x5439E0); }
-WRAPPER void CCranes::Save(uint8*, uint32*) { EAXJMP(0x545210); }
-WRAPPER void CranesLoad(uint8*, uint32) { EAXJMP(0x5454d0); }
diff --git a/src/control/Cranes.h b/src/control/Cranes.h
deleted file mode 100644
index b40454ea..00000000
--- a/src/control/Cranes.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-#include "common.h"
-
-class CVehicle;
-class CEntity;
-class CObject;
-
-class CCrane
-{
-public:
-	CEntity *m_pObject;
-	CObject *m_pMagnet;
-	int m_nAudioEntity;
-	float m_fPickupX1;
-	float m_fPickupX2;
-	float m_fPickupY1;
-	float m_fPickupY2;
-	CVector m_vecDropoffTarget;
-	float m_fDropoffHeading;
-	float m_fPickupAngle;
-	float m_fDropoffAngle;
-	float m_fPickupDistance;
-	float m_fDropoffDistance;
-	float m_fAngle;
-	float m_fDistance;
-	float m_fHeight;
-	float m_fHookOffset;
-	float m_fHookHeight;
-	CVector m_vecHookInitPos;
-	CVector m_vecHookCurPos;
-	float m_fHookVelocityX;
-	float m_fHookVelocityY;
-	CVehicle *m_pVehiclePickedUp;
-	int m_nUpdateTimer;
-	char m_bCraneActive;
-	char m_bCraneStatus;
-	char m_bVehiclesCollected;
-	char m_bIsCrusher;
-	char m_bIsMilitaryCrane;
-	char field_125;
-	char m_bNotMilitaryCrane;
-	char gap_127[1];
-};
-
-static_assert(sizeof(CCrane) == 128, "CCrane: error");
-
-class CCranes
-{
-public:
-	static bool IsThisCarBeingTargettedByAnyCrane(CVehicle*);
-	static bool IsThisCarBeingCarriedByAnyCrane(CVehicle*);
-	static bool IsThisCarPickedUp(float, float, CVehicle*);
-	static bool HaveAllCarsBeenCollectedByMilitaryCrane();
-	static void ActivateCrane(float, float, float, float, float, float, float, float, bool, bool, float, float);
-	static void DeActivateCrane(float, float);
-	static void InitCranes(void);
-	static void UpdateCranes(void);
-	static void Save(uint8*, uint32*);
-};
-
-void CranesLoad(uint8*, uint32);	// is this really outside CCranes?
diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp
index 0abae7d6..8e0ea02d 100644
--- a/src/control/GameLogic.cpp
+++ b/src/control/GameLogic.cpp
@@ -1,294 +1,294 @@
 #include "common.h"
 #include "patcher.h"
-#include "GameLogic.h"
-#include "Clock.h"
-#include "Stats.h"
-#include "Pickups.h"
-#include "Timer.h"
-#include "Streaming.h"
-#include "CutsceneMgr.h"
-#include "World.h"
-#include "PlayerPed.h"
-#include "Wanted.h"
-#include "Camera.h"
-#include "Messages.h"
-#include "CarCtrl.h"
-#include "Restart.h"
-#include "Pad.h"
-#include "References.h"
-#include "Fire.h"
-#include "Script.h"
-#include "Garages.h"
-
-uint8 CGameLogic::ActivePlayers; // 0x95CD5E
-
-void
-CGameLogic::InitAtStartOfGame()
-{
-	ActivePlayers = 1;
-}
-
-void
-CGameLogic::PassTime(uint32 time)
-{
-	int32 minutes, hours, days;
-
-	minutes = time + CClock::GetMinutes();
-	hours = CClock::GetHours();
-
-	for (; minutes >= 60; minutes -= 60)
-		hours++;
-
-	if (hours > 23) {
-		days = CStats::DaysPassed;
-		for (; hours >= 24; hours -= 24)
-			days++;
-		CStats::DaysPassed = days;
-	}
-
-	CClock::SetGameClock(hours, minutes);
-	CPickups::PassTime(time * 1000);
-}
-
-void 
-CGameLogic::SortOutStreamingAndMemory(const CVector &pos)
-{
-	CTimer::Stop();
-	CStreaming::FlushRequestList();
-	CStreaming::DeleteRwObjectsAfterDeath(pos);
-	CStreaming::RemoveUnusedModelsInLoadedList();
-	CGame::DrasticTidyUpMemory(true);
-	CStreaming::LoadScene(pos);
-	CTimer::Update();
-}
-
-void
-CGameLogic::Update()
-{
-	CVector vecRestartPos;
-	float fRestartFloat;
-
-	if (CCutsceneMgr::IsCutsceneProcessing()) return;
-
-	CPlayerInfo &pPlayerInfo = CWorld::Players[CWorld::PlayerInFocus];
-	switch (pPlayerInfo.m_WBState) {
-	case WBSTATE_PLAYING:
-		if (pPlayerInfo.m_pPed->m_nPedState == PED_DEAD) {
-			pPlayerInfo.m_pPed->ClearAdrenaline();
-			pPlayerInfo.KillPlayer();
-		}
-		if (pPlayerInfo.m_pPed->m_nPedState == PED_ARRESTED) {
-			pPlayerInfo.m_pPed->ClearAdrenaline();
-			pPlayerInfo.ArrestPlayer();
-		}
-		break;
-	case WBSTATE_WASTED:
-		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
-			TheCamera.SetFadeColour(200, 200, 200);
-			TheCamera.Fade(2.0f, FADE_OUT);
-		}
-
-		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
-			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
-			if (pPlayerInfo.m_bGetOutOfHospitalFree) {
-				pPlayerInfo.m_bGetOutOfHospitalFree = false;
-			} else {
-				pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - 1000);
-				pPlayerInfo.m_pPed->ClearWeapons();
-			}
-
-			if (pPlayerInfo.m_pPed->bInVehicle) {
-				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
-				if (pVehicle != nil) {
-					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
-						pVehicle->pDriver = nil;
-						if (pVehicle->m_status != STATUS_WRECKED)
-							pVehicle->m_status = STATUS_ABANDONED;
-					} else
-						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
-				}
-			}
-			CEventList::Initialise();
-			CMessages::ClearMessages();
-			CCarCtrl::ClearInterestingVehicleList();
-			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
-			CRestart::FindClosestHospitalRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
-			CRestart::OverrideHospitalLevel = LEVEL_NONE;
-			CRestart::OverridePoliceStationLevel = LEVEL_NONE;
-			PassTime(720);
-			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
-			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
-			TheCamera.m_fCamShakeForce = 0.0f;
-			TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
-			CPad::GetPad(0)->StopShaking(0);
-			CReferences::RemoveReferencesToPlayer();
-			CCarCtrl::CountDownToCarsAtStart = 2;
-			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
-			if (CRestart::bFadeInAfterNextDeath) { 
-				TheCamera.SetFadeColour(200, 200, 200);
-				TheCamera.Fade(4.0f, FADE_IN);
-			} else CRestart::bFadeInAfterNextDeath = true;
-		}
-		break;
-	case WBSTATE_BUSTED:
-		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
-			TheCamera.SetFadeColour(0, 0, 0);
-			TheCamera.Fade(2.0f, FADE_OUT);
-		}
-		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
-			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
-			int takeMoney;
-
-			switch (pPlayerInfo.m_pPed->m_pWanted->m_nWantedLevel) {
-			case 0:
-			case 1:
-				takeMoney = 100;
-				break;
-			case 2:
-				takeMoney = 200;
-				break;
-			case 3:
-				takeMoney = 400;
-				break;
-			case 4:
-				takeMoney = 600;
-				break;
-			case 5:
-				takeMoney = 900;
-				break;
-			case 6:
-				takeMoney = 1500;
-				break;
-			}
-			if (pPlayerInfo.m_bGetOutOfJailFree) {
-				pPlayerInfo.m_bGetOutOfJailFree = false;
-			} else {
-				pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - takeMoney);
-				pPlayerInfo.m_pPed->ClearWeapons();
-			}
-
-			if (pPlayerInfo.m_pPed->bInVehicle) {
-				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
-				if (pVehicle != nil) {
-					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
-						pVehicle->pDriver = nil;
-						if (pVehicle->m_status != STATUS_WRECKED)
-							pVehicle->m_status = STATUS_ABANDONED;
-					}
-					else
-						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
-				}
-			}
-			CEventList::Initialise();
-			CMessages::ClearMessages();
-			CCarCtrl::ClearInterestingVehicleList();
-			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
-			CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
-			CRestart::OverrideHospitalLevel = LEVEL_NONE;
-			CRestart::OverridePoliceStationLevel = LEVEL_NONE;
-			PassTime(720);
-			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
-			pPlayerInfo.m_pPed->ClearWeapons();
-			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
-			TheCamera.m_fCamShakeForce = 0.0f;
-			TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
-			CPad::GetPad(0)->StopShaking(0);
-			CReferences::RemoveReferencesToPlayer();
-			CCarCtrl::CountDownToCarsAtStart = 2;
-			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
-			if (CRestart::bFadeInAfterNextArrest) {
-				TheCamera.SetFadeColour(0, 0, 0);
-				TheCamera.Fade(4.0f, FADE_IN);
-			} else CRestart::bFadeInAfterNextArrest = true;
-		}
-		break;
-	case WBSTATE_FAILED_CRITICAL_MISSION:
-		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800 && CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800) {
-			TheCamera.SetFadeColour(0, 0, 0);
-			TheCamera.Fade(2.0f, FADE_OUT);
-		}
-		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
-			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
-			if (pPlayerInfo.m_pPed->bInVehicle) {
-				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
-				if (pVehicle != nil) {
-					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
-						pVehicle->pDriver = nil;
-						if (pVehicle->m_status != STATUS_WRECKED)
-							pVehicle->m_status = STATUS_ABANDONED;
-					} else
-						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
-				}
-			}
-			CEventList::Initialise();
-			CMessages::ClearMessages();
-			CCarCtrl::ClearInterestingVehicleList();
-			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
-			CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
-			CRestart::OverridePoliceStationLevel = LEVEL_NONE;
-			CRestart::OverrideHospitalLevel = LEVEL_NONE;
-			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
-			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
-			TheCamera.m_fCamShakeForce = 0.0f;
-			TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
-			CPad::GetPad(0)->StopShaking(0);
-			CReferences::RemoveReferencesToPlayer();
-			CCarCtrl::CountDownToCarsAtStart = 2;
-			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
-			TheCamera.SetFadeColour(0, 0, 0);
-			TheCamera.Fade(4.0f, FADE_IN);
-		}
-		break;
-	case 4:
-		return;
-	}
-}
-
-void
-CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *pPlayerPed, CVector pos, float angle)
-{
-	pPlayerPed->m_fHealth = 100.0f;
-	pPlayerPed->m_fArmour = 0.0f;
-	pPlayerPed->bIsVisible = true;
-	pPlayerPed->m_bloodyFootprintCountOrDeathTime = 0;
-	pPlayerPed->bDoBloodyFootprints = false;
-	pPlayerPed->ClearAdrenaline();
-	pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
-	if (pPlayerPed->m_pFire)
-		pPlayerPed->m_pFire->Extinguish();
-	pPlayerPed->bInVehicle = false;
-	pPlayerPed->m_pMyVehicle = nil;
-	pPlayerPed->m_pVehicleAnim = nil;
-	pPlayerPed->m_pWanted->Reset();
-	pPlayerPed->RestartNonPartialAnims();
-	pPlayerPed->GetPlayerInfoForThisPlayerPed()->MakePlayerSafe(false);
-	pPlayerPed->bRemoveFromWorld = false;
-	pPlayerPed->ClearWeaponTarget();
-	pPlayerPed->SetInitialState();
-	CCarCtrl::ClearInterestingVehicleList();
-
-	pos.z += 1.0f;
-	pPlayerPed->Teleport(pos);
-	pPlayerPed->SetMoveSpeed(CVector(0.0f, 0.0f, 0.0f));
-
-	pPlayerPed->m_fRotationCur = DEGTORAD(angle);
-	pPlayerPed->m_fRotationDest = pPlayerPed->m_fRotationCur;
-	pPlayerPed->SetHeading(pPlayerPed->m_fRotationCur);
-	CTheScripts::ClearSpaceForMissionEntity(pos, pPlayerPed);
-	CWorld::ClearExcitingStuffFromArea(pos, 4000.0, 1);
-	pPlayerPed->RestoreHeadingRate();
-	TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString();
-	CReferences::RemoveReferencesToPlayer();
-	CGarages::PlayerArrestedOrDied();
-	CStats::CheckPointReachedUnsuccessfully();
-	CWorld::Remove(pPlayerPed);
-	CWorld::Add(pPlayerPed);
-}
-
+#include "GameLogic.h"
+#include "Clock.h"
+#include "Stats.h"
+#include "Pickups.h"
+#include "Timer.h"
+#include "Streaming.h"
+#include "CutsceneMgr.h"
+#include "World.h"
+#include "PlayerPed.h"
+#include "Wanted.h"
+#include "Camera.h"
+#include "Messages.h"
+#include "CarCtrl.h"
+#include "Restart.h"
+#include "Pad.h"
+#include "References.h"
+#include "Fire.h"
+#include "Script.h"
+#include "Garages.h"
+
+uint8 CGameLogic::ActivePlayers; // 0x95CD5E
+
+void
+CGameLogic::InitAtStartOfGame()
+{
+	ActivePlayers = 1;
+}
+
+void
+CGameLogic::PassTime(uint32 time)
+{
+	int32 minutes, hours, days;
+
+	minutes = time + CClock::GetMinutes();
+	hours = CClock::GetHours();
+
+	for (; minutes >= 60; minutes -= 60)
+		hours++;
+
+	if (hours > 23) {
+		days = CStats::DaysPassed;
+		for (; hours >= 24; hours -= 24)
+			days++;
+		CStats::DaysPassed = days;
+	}
+
+	CClock::SetGameClock(hours, minutes);
+	CPickups::PassTime(time * 1000);
+}
+
+void 
+CGameLogic::SortOutStreamingAndMemory(const CVector &pos)
+{
+	CTimer::Stop();
+	CStreaming::FlushRequestList();
+	CStreaming::DeleteRwObjectsAfterDeath(pos);
+	CStreaming::RemoveUnusedModelsInLoadedList();
+	CGame::DrasticTidyUpMemory(true);
+	CStreaming::LoadScene(pos);
+	CTimer::Update();
+}
+
+void
+CGameLogic::Update()
+{
+	CVector vecRestartPos;
+	float fRestartFloat;
+
+	if (CCutsceneMgr::IsCutsceneProcessing()) return;
+
+	CPlayerInfo &pPlayerInfo = CWorld::Players[CWorld::PlayerInFocus];
+	switch (pPlayerInfo.m_WBState) {
+	case WBSTATE_PLAYING:
+		if (pPlayerInfo.m_pPed->m_nPedState == PED_DEAD) {
+			pPlayerInfo.m_pPed->ClearAdrenaline();
+			pPlayerInfo.KillPlayer();
+		}
+		if (pPlayerInfo.m_pPed->m_nPedState == PED_ARRESTED) {
+			pPlayerInfo.m_pPed->ClearAdrenaline();
+			pPlayerInfo.ArrestPlayer();
+		}
+		break;
+	case WBSTATE_WASTED:
+		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
+			TheCamera.SetFadeColour(200, 200, 200);
+			TheCamera.Fade(2.0f, FADE_OUT);
+		}
+
+		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
+			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
+			if (pPlayerInfo.m_bGetOutOfHospitalFree) {
+				pPlayerInfo.m_bGetOutOfHospitalFree = false;
+			} else {
+				pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - 1000);
+				pPlayerInfo.m_pPed->ClearWeapons();
+			}
+
+			if (pPlayerInfo.m_pPed->bInVehicle) {
+				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
+				if (pVehicle != nil) {
+					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
+						pVehicle->pDriver = nil;
+						if (pVehicle->m_status != STATUS_WRECKED)
+							pVehicle->m_status = STATUS_ABANDONED;
+					} else
+						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
+				}
+			}
+			CEventList::Initialise();
+			CMessages::ClearMessages();
+			CCarCtrl::ClearInterestingVehicleList();
+			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
+			CRestart::FindClosestHospitalRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
+			CRestart::OverrideHospitalLevel = LEVEL_NONE;
+			CRestart::OverridePoliceStationLevel = LEVEL_NONE;
+			PassTime(720);
+			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
+			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
+			TheCamera.m_fCamShakeForce = 0.0f;
+			TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
+			CPad::GetPad(0)->StopShaking(0);
+			CReferences::RemoveReferencesToPlayer();
+			CCarCtrl::CountDownToCarsAtStart = 2;
+			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
+			if (CRestart::bFadeInAfterNextDeath) { 
+				TheCamera.SetFadeColour(200, 200, 200);
+				TheCamera.Fade(4.0f, FADE_IN);
+			} else CRestart::bFadeInAfterNextDeath = true;
+		}
+		break;
+	case WBSTATE_BUSTED:
+		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
+			TheCamera.SetFadeColour(0, 0, 0);
+			TheCamera.Fade(2.0f, FADE_OUT);
+		}
+		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
+			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
+			int takeMoney;
+
+			switch (pPlayerInfo.m_pPed->m_pWanted->m_nWantedLevel) {
+			case 0:
+			case 1:
+				takeMoney = 100;
+				break;
+			case 2:
+				takeMoney = 200;
+				break;
+			case 3:
+				takeMoney = 400;
+				break;
+			case 4:
+				takeMoney = 600;
+				break;
+			case 5:
+				takeMoney = 900;
+				break;
+			case 6:
+				takeMoney = 1500;
+				break;
+			}
+			if (pPlayerInfo.m_bGetOutOfJailFree) {
+				pPlayerInfo.m_bGetOutOfJailFree = false;
+			} else {
+				pPlayerInfo.m_nMoney = max(0, pPlayerInfo.m_nMoney - takeMoney);
+				pPlayerInfo.m_pPed->ClearWeapons();
+			}
+
+			if (pPlayerInfo.m_pPed->bInVehicle) {
+				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
+				if (pVehicle != nil) {
+					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
+						pVehicle->pDriver = nil;
+						if (pVehicle->m_status != STATUS_WRECKED)
+							pVehicle->m_status = STATUS_ABANDONED;
+					}
+					else
+						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
+				}
+			}
+			CEventList::Initialise();
+			CMessages::ClearMessages();
+			CCarCtrl::ClearInterestingVehicleList();
+			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
+			CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
+			CRestart::OverrideHospitalLevel = LEVEL_NONE;
+			CRestart::OverridePoliceStationLevel = LEVEL_NONE;
+			PassTime(720);
+			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
+			pPlayerInfo.m_pPed->ClearWeapons();
+			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
+			TheCamera.m_fCamShakeForce = 0.0f;
+			TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
+			CPad::GetPad(0)->StopShaking(0);
+			CReferences::RemoveReferencesToPlayer();
+			CCarCtrl::CountDownToCarsAtStart = 2;
+			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
+			if (CRestart::bFadeInAfterNextArrest) {
+				TheCamera.SetFadeColour(0, 0, 0);
+				TheCamera.Fade(4.0f, FADE_IN);
+			} else CRestart::bFadeInAfterNextArrest = true;
+		}
+		break;
+	case WBSTATE_FAILED_CRITICAL_MISSION:
+		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800 && CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800) {
+			TheCamera.SetFadeColour(0, 0, 0);
+			TheCamera.Fade(2.0f, FADE_OUT);
+		}
+		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
+			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
+			if (pPlayerInfo.m_pPed->bInVehicle) {
+				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
+				if (pVehicle != nil) {
+					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
+						pVehicle->pDriver = nil;
+						if (pVehicle->m_status != STATUS_WRECKED)
+							pVehicle->m_status = STATUS_ABANDONED;
+					} else
+						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
+				}
+			}
+			CEventList::Initialise();
+			CMessages::ClearMessages();
+			CCarCtrl::ClearInterestingVehicleList();
+			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
+			CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
+			CRestart::OverridePoliceStationLevel = LEVEL_NONE;
+			CRestart::OverrideHospitalLevel = LEVEL_NONE;
+			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
+			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
+			TheCamera.m_fCamShakeForce = 0.0f;
+			TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
+			CPad::GetPad(0)->StopShaking(0);
+			CReferences::RemoveReferencesToPlayer();
+			CCarCtrl::CountDownToCarsAtStart = 2;
+			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
+			TheCamera.SetFadeColour(0, 0, 0);
+			TheCamera.Fade(4.0f, FADE_IN);
+		}
+		break;
+	case 4:
+		return;
+	}
+}
+
+void
+CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *pPlayerPed, CVector pos, float angle)
+{
+	pPlayerPed->m_fHealth = 100.0f;
+	pPlayerPed->m_fArmour = 0.0f;
+	pPlayerPed->bIsVisible = true;
+	pPlayerPed->m_bloodyFootprintCountOrDeathTime = 0;
+	pPlayerPed->bDoBloodyFootprints = false;
+	pPlayerPed->ClearAdrenaline();
+	pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
+	if (pPlayerPed->m_pFire)
+		pPlayerPed->m_pFire->Extinguish();
+	pPlayerPed->bInVehicle = false;
+	pPlayerPed->m_pMyVehicle = nil;
+	pPlayerPed->m_pVehicleAnim = nil;
+	pPlayerPed->m_pWanted->Reset();
+	pPlayerPed->RestartNonPartialAnims();
+	pPlayerPed->GetPlayerInfoForThisPlayerPed()->MakePlayerSafe(false);
+	pPlayerPed->bRemoveFromWorld = false;
+	pPlayerPed->ClearWeaponTarget();
+	pPlayerPed->SetInitialState();
+	CCarCtrl::ClearInterestingVehicleList();
+
+	pos.z += 1.0f;
+	pPlayerPed->Teleport(pos);
+	pPlayerPed->SetMoveSpeed(CVector(0.0f, 0.0f, 0.0f));
+
+	pPlayerPed->m_fRotationCur = DEGTORAD(angle);
+	pPlayerPed->m_fRotationDest = pPlayerPed->m_fRotationCur;
+	pPlayerPed->SetHeading(pPlayerPed->m_fRotationCur);
+	CTheScripts::ClearSpaceForMissionEntity(pos, pPlayerPed);
+	CWorld::ClearExcitingStuffFromArea(pos, 4000.0, 1);
+	pPlayerPed->RestoreHeadingRate();
+	TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString();
+	CReferences::RemoveReferencesToPlayer();
+	CGarages::PlayerArrestedOrDied();
+	CStats::CheckPointReachedUnsuccessfully();
+	CWorld::Remove(pPlayerPed);
+	CWorld::Add(pPlayerPed);
+}
+
 STARTPATCHES
 	InjectHook(0x4213F0, &CGameLogic::InitAtStartOfGame, PATCH_JUMP);
 	InjectHook(0x421C00, &CGameLogic::PassTime, PATCH_JUMP);
 	InjectHook(0x421A20, &CGameLogic::SortOutStreamingAndMemory, PATCH_JUMP);
 	InjectHook(0x421400, &CGameLogic::Update, PATCH_JUMP);
-	InjectHook(0x421A60, &CGameLogic::RestorePlayerStuffDuringResurrection, PATCH_JUMP);
+	InjectHook(0x421A60, &CGameLogic::RestorePlayerStuffDuringResurrection, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/control/GameLogic.h b/src/control/GameLogic.h
index db626558..43e244a3 100644
--- a/src/control/GameLogic.h
+++ b/src/control/GameLogic.h
@@ -1,13 +1,13 @@
-#pragma once
-
-class CGameLogic
-{
-public:
-	static void InitAtStartOfGame();
-	static void PassTime(uint32 time);
-	static void SortOutStreamingAndMemory(const CVector &pos);
-	static void Update();
-	static void RestorePlayerStuffDuringResurrection(class CPlayerPed *pPlayerPed, CVector pos, float angle);
-
-	static uint8 ActivePlayers;
+#pragma once
+
+class CGameLogic
+{
+public:
+	static void InitAtStartOfGame();
+	static void PassTime(uint32 time);
+	static void SortOutStreamingAndMemory(const CVector &pos);
+	static void Update();
+	static void RestorePlayerStuffDuringResurrection(class CPlayerPed *pPlayerPed, CVector pos, float angle);
+
+	static uint8 ActivePlayers;
 };
\ No newline at end of file
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 6a91da76..e4b2aee3 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -126,7 +126,6 @@ uint32& CGarages::MessageEndTime = *(uint32*)0x8F597C;
 uint32& CGarages::NumGarages = *(uint32*)0x8F29F4;
 bool& CGarages::PlayerInGarage = *(bool*)0x95CD83;
 int32& CGarages::PoliceCarsCollected = *(int32*)0x941444;
-uint32& CGarages::GarageToBeTidied = *(uint32*)0x623570;
 CStoredCar(&CGarages::aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA210;
 CStoredCar(&CGarages::aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA300;
 CStoredCar(&CGarages::aCarsInSafeHouse3)[NUM_GARAGE_STORED_CARS] = *(CStoredCar(*)[NUM_GARAGE_STORED_CARS]) * (uintptr*)0x6FA3F0;
@@ -322,6 +321,9 @@ void CGarage::Update()
 					}
 				}
 			}
+			break;
+		default:
+			break;
 		}
 	}
 	if (m_bDeactivated && m_eGarageState == GS_FULLYCLOSED)
@@ -408,11 +410,11 @@ void CGarage::Update()
 					if (!((CAutomobile*)(FindPlayerVehicle()))->bFixedColour) {
 						uint8 colour1, colour2;
 						uint16 attempt;
-						((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2);
+						FindPlayerVehicle()->GetModelInfo()->ChooseVehicleColour(colour1, colour2);
 						for (attempt = 0; attempt < 10; attempt++) {
 							if (colour1 != FindPlayerVehicle()->m_currentColour1 || colour2 != FindPlayerVehicle()->m_currentColour2)
 								break;
-							((CVehicleModelInfo*)CModelInfo::GetModelInfo(FindPlayerVehicle()->GetModelIndex()))->ChooseVehicleColour(colour1, colour2);
+							FindPlayerVehicle()->GetModelInfo()->ChooseVehicleColour(colour1, colour2);
 						}
 						bChangedColour = (attempt < 10);
 						FindPlayerVehicle()->m_currentColour1 = colour1;
@@ -490,7 +492,7 @@ void CGarage::Update()
 					break;
 				}
 				if (!CGarages::BombsAreFree && CWorld::Players[CWorld::PlayerInFocus].m_nMoney < BOMB_PRICE) {
-					CGarages::TriggerMessage("GA_4", -1, 4000, -1); // "Car bombs are $1000 each"
+					CGarages::TriggerMessage("GA_4", -1, 4000, -1); // "Car bombs are $1000 each" - weird that the price is hardcoded in message
 					m_eGarageState = GS_OPENEDCONTAINSCAR;
 					DMAudio.PlayFrontEndSound(SOUND_GARAGE_NO_MONEY, 1);
 					break;
@@ -524,7 +526,7 @@ void CGarage::Update()
 					((CAutomobile*)(FindPlayerVehicle()))->m_pBombRigger = FindPlayerPed();
 					if (m_eGarageType == GARAGE_BOMBSHOP3)
 						CGarages::GivePlayerDetonator();
-					CStats::KgOfExplosivesUsed += KGS_OF_EXPLOSIVES_IN_BOMB;
+					CStats::KgsOfExplosivesUsed += KGS_OF_EXPLOSIVES_IN_BOMB;
 				}
 				switch (m_eGarageType) {
 				case GARAGE_BOMBSHOP1:
@@ -1184,7 +1186,7 @@ bool CGarage::IsEntityEntirelyInside(CEntity * pEntity)
 	if (pEntity->GetPosition().x < m_fX1 || pEntity->GetPosition().x > m_fX2 ||
 		pEntity->GetPosition().y < m_fY1 || pEntity->GetPosition().y > m_fY2)
 		return false;
-	CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+	CColModel* pColModel = pEntity->GetColModel();
 	for (int i = 0; i < pColModel->numSpheres; i++) {
 		CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
 		float radius = pColModel->spheres[i].radius;
@@ -1201,7 +1203,7 @@ bool CGarage::IsEntityEntirelyInside3D(CEntity * pEntity, float fMargin)
 		pEntity->GetPosition().y < m_fY1 - fMargin || pEntity->GetPosition().y > m_fY2 + fMargin ||
 		pEntity->GetPosition().z < m_fZ1 - fMargin || pEntity->GetPosition().z > m_fZ2 + fMargin)
 		return false;
-	CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+	CColModel* pColModel = pEntity->GetColModel();
 	for (int i = 0; i < pColModel->numSpheres; i++) {
 		CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
 		float radius = pColModel->spheres[i].radius;
@@ -1218,7 +1220,7 @@ bool CGarage::IsEntityEntirelyOutside(CEntity * pEntity, float fMargin)
 	if (pEntity->GetPosition().x > m_fX1 - fMargin && pEntity->GetPosition().x < m_fX2 + fMargin &&
 		pEntity->GetPosition().y > m_fY1 - fMargin && pEntity->GetPosition().y < m_fY2 + fMargin)
 		return false;
-	CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+	CColModel* pColModel = pEntity->GetColModel();
 	for (int i = 0; i < pColModel->numSpheres; i++) {
 		CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
 		float radius = pColModel->spheres[i].radius;
@@ -1250,7 +1252,7 @@ bool CGarage::IsEntityTouching3D(CEntity * pEntity)
 		pEntity->GetPosition().y - radius < m_fY1 || pEntity->GetPosition().y + radius > m_fY2 ||
 		pEntity->GetPosition().z - radius < m_fZ1 || pEntity->GetPosition().z + radius > m_fZ2)
 		return false;
-	CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+	CColModel* pColModel = pEntity->GetColModel();
 	for (int i = 0; i < pColModel->numSpheres; i++) {
 		CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
 		radius = pColModel->spheres[i].radius;
@@ -1264,7 +1266,7 @@ bool CGarage::IsEntityTouching3D(CEntity * pEntity)
 
 bool CGarage::EntityHasASphereWayOutsideGarage(CEntity * pEntity, float fMargin)
 {
-	CColModel* pColModel = CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel();
+	CColModel* pColModel = pEntity->GetColModel();
 	for (int i = 0; i < pColModel->numSpheres; i++) {
 		CVector pos = pEntity->GetMatrix() * pColModel->spheres[i].center;
 		float radius = pColModel->spheres[i].radius;
@@ -1285,7 +1287,7 @@ bool CGarage::IsAnyOtherCarTouchingGarage(CVehicle * pException)
 			continue;
 		if (!IsEntityTouching3D(pVehicle))
 			continue;
-		CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+		CColModel* pColModel = pVehicle->GetColModel();
 		for (int i = 0; i < pColModel->numSpheres; i++) {
 			CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
 			float radius = pColModel->spheres[i].radius;
@@ -1307,7 +1309,7 @@ bool CGarage::IsAnyOtherPedTouchingGarage(CPed * pException)
 			continue;
 		if (!IsEntityTouching3D(pPed))
 			continue;
-		CColModel* pColModel = CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetColModel();
+		CColModel* pColModel = pException->GetColModel();
 		for (int i = 0; i < pColModel->numSpheres; i++) {
 			CVector pos = pPed->GetMatrix() * pColModel->spheres[i].center;
 			float radius = pColModel->spheres[i].radius;
@@ -1329,7 +1331,7 @@ bool CGarage::IsAnyCarBlockingDoor()
 			continue;
 		if (!IsEntityTouching3D(pVehicle))
 			continue;
-		CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+		CColModel* pColModel = pVehicle->GetColModel();
 		for (int i = 0; i < pColModel->numSpheres; i++) {
 			CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
 			float radius = pColModel->spheres[i].radius;
@@ -1677,7 +1679,7 @@ float CGarage::CalcDistToGarageRectangleSquared(float X, float Y)
 	else
 		distX = 0.0f;
 	if (Y < m_fY1)
-		distY = m_fY1 - X;
+		distY = m_fY1 - Y;
 	else if (Y > m_fY2)
 		distY = Y - m_fY2;
 	else
@@ -1698,8 +1700,8 @@ float CGarage::CalcSmallestDistToGarageDoorSquared(float X, float Y)
 
 void CGarage::FindDoorsEntities()
 {
-	m_pDoor1 = false;
-	m_pDoor2 = false;
+	m_pDoor1 = nil;
+	m_pDoor2 = nil;
 	int xstart = max(0, CWorld::GetSectorIndexX(m_fX1));
 	int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fX2));
 	int ystart = max(0, CWorld::GetSectorIndexY(m_fY1));
@@ -1992,7 +1994,7 @@ void CGarage::TidyUpGarageClose()
 			continue;
 		bool bRemove = false;
 		if (m_eGarageState != GS_FULLYCLOSED) {
-			CColModel* pColModel = CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel();
+			CColModel* pColModel = pVehicle->GetColModel();
 			for (int i = 0; i < pColModel->numSpheres; i++) {
 				CVector pos = pVehicle->GetMatrix() * pColModel->spheres[i].center;
 				float radius = pColModel->spheres[i].radius;
@@ -2106,7 +2108,7 @@ void CGarages::CloseHideOutGaragesBeforeSave()
 			aGarages[i].m_eGarageType != GARAGE_HIDEOUT_THREE)
 			continue;
 		if (aGarages[i].m_eGarageState != GS_FULLYCLOSED &&
-			aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor()) {
+			(aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor())) {
 			aGarages[i].m_eGarageState = GS_FULLYCLOSED;
 			switch (aGarages[i].m_eGarageType) {
 			case GARAGE_HIDEOUT_ONE:
@@ -2227,6 +2229,7 @@ void CGarages::SetAllDoorsBackToOriginalHeight()
 void CGarages::Save(uint8 * buf, uint32 * size)
 {
 #ifdef FIX_GARAGE_SIZE
+	INITSAVEBUF
 	*size = (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
 #else
 	* size = 5484;
@@ -2248,6 +2251,9 @@ void CGarages::Save(uint8 * buf, uint32 * size)
 	}
 	for (int i = 0; i < NUM_GARAGES; i++)
 		WriteSaveBuf(buf, aGarages[i]);
+#ifdef FIX_GARAGE_SIZE
+	VALIDATESAVEBUF(*size);
+#endif
 }
 
 CStoredCar::CStoredCar(const CStoredCar & other)
@@ -2271,6 +2277,7 @@ CStoredCar::CStoredCar(const CStoredCar & other)
 void CGarages::Load(uint8* buf, uint32 size)
 {
 #ifdef FIX_GARAGE_SIZE
+	INITSAVEBUF
 	assert(size == (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
 #else
 	assert(size == 5484);
@@ -2303,6 +2310,9 @@ void CGarages::Load(uint8* buf, uint32 size)
 		else
 			aGarages[i].UpdateDoorsHeight();
 	}
+#ifdef FIX_GARAGE_SIZE
+	VALIDATESAVEBUF(size);
+#endif
 }
 
 bool
@@ -2345,8 +2355,7 @@ CGarages::IsModelIndexADoor(uint32 id)
 
 
 STARTPATCHES
-	InjectHook(0x426B20, CGarages::TriggerMessage, PATCH_JUMP); // CCrane::Update, CCrane::FindCarInSectorList
 	InjectHook(0x427AB0, CGarages::IsPointInAGarageCameraZone, PATCH_JUMP); // CCamera::CamControl
 	InjectHook(0x427BC0, CGarages::CameraShouldBeOutside, PATCH_JUMP); // CCamera::CamControl
 	InjectHook(0x428940, CGarages::Load, PATCH_JUMP); // GenericLoad
-ENDPATCHES
\ No newline at end of file
+ENDPATCHES
diff --git a/src/control/Garages.h b/src/control/Garages.h
index e3864a48..26e7a89a 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -194,7 +194,6 @@ class CGarages
 	static uint32 &NumGarages;
 	static bool &PlayerInGarage;
 	static int32 &PoliceCarsCollected;
-	static uint32 &GarageToBeTidied;
 	static CGarage(&aGarages)[NUM_GARAGES];
 	static CStoredCar(&aCarsInSafeHouse1)[NUM_GARAGE_STORED_CARS];
 	static CStoredCar(&aCarsInSafeHouse2)[NUM_GARAGE_STORED_CARS];
diff --git a/src/control/OnscreenTimer.h b/src/control/OnscreenTimer.h
index b1e0e622..fb139266 100644
--- a/src/control/OnscreenTimer.h
+++ b/src/control/OnscreenTimer.h
@@ -1,49 +1,49 @@
-#pragma once
-
-enum
-{
-	COUNTER_DISPLAY_NUMBER,
-	COUNTER_DISPLAY_BAR,
-};
-
-class COnscreenTimerEntry
-{
-public:
-	uint32 m_nTimerOffset;
-	uint32 m_nCounterOffset;
-	char m_aTimerText[10];
-	char m_aCounterText[10];
-	uint16 m_nType;
-	char m_bCounterBuffer[42];
-	char m_bTimerBuffer[42];
-	bool m_bTimerProcessed;
-	bool m_bCounterProcessed;
-
-	void Process();
-	bool ProcessForDisplay();
-
-	void ProcessForDisplayClock();
-	void ProcessForDisplayCounter();
-};
-
-static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error");
-
-class COnscreenTimer
-{
-public:
-	COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES];
-	bool m_bProcessed;
-	bool m_bDisabled;
-
-	void Init();
-	void Process();
-	void ProcessForDisplay();
-
-	void ClearCounter(uint32 offset);
-	void ClearClock(uint32 offset);
-
-	void AddCounter(uint32 offset, uint16 type, char* text);
-	void AddClock(uint32 offset, char* text);
-};
-
+#pragma once
+
+enum
+{
+	COUNTER_DISPLAY_NUMBER,
+	COUNTER_DISPLAY_BAR,
+};
+
+class COnscreenTimerEntry
+{
+public:
+	uint32 m_nTimerOffset;
+	uint32 m_nCounterOffset;
+	char m_aTimerText[10];
+	char m_aCounterText[10];
+	uint16 m_nType;
+	char m_bCounterBuffer[42];
+	char m_bTimerBuffer[42];
+	bool m_bTimerProcessed;
+	bool m_bCounterProcessed;
+
+	void Process();
+	bool ProcessForDisplay();
+
+	void ProcessForDisplayClock();
+	void ProcessForDisplayCounter();
+};
+
+static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error");
+
+class COnscreenTimer
+{
+public:
+	COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES];
+	bool m_bProcessed;
+	bool m_bDisabled;
+
+	void Init();
+	void Process();
+	void ProcessForDisplay();
+
+	void ClearCounter(uint32 offset);
+	void ClearClock(uint32 offset);
+
+	void AddCounter(uint32 offset, uint16 type, char* text);
+	void AddClock(uint32 offset, char* text);
+};
+
 static_assert(sizeof(COnscreenTimer) == 0x78, "COnscreenTimer: error");
\ No newline at end of file
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index 608a209a..61cd3d4e 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -5,8 +5,13 @@
 #include "Camera.h"
 #include "Vehicle.h"
 #include "World.h"
+#include "Lines.h"	// for debug
 #include "PathFind.h"
 
+bool gbShowPedPaths;
+bool gbShowCarPaths;
+bool gbShowCarPathsLinks;
+
 CPathFind &ThePaths = *(CPathFind*)0x8F6754;
 
 WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); }
@@ -466,20 +471,20 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor
 				// IMPROVE: use a goto here
 				// Find existing car path link
 				for(k = 0; k < m_numCarPathLinks; k++){
-					if(m_carPathLinks[k].dirX == tempnodes[j].dirX &&
-					   m_carPathLinks[k].dirY == tempnodes[j].dirY &&
-					   m_carPathLinks[k].posX == tempnodes[j].pos.x &&
-					   m_carPathLinks[k].posY == tempnodes[j].pos.y){
+					if(m_carPathLinks[k].dir.x == tempnodes[j].dirX &&
+					   m_carPathLinks[k].dir.y == tempnodes[j].dirY &&
+					   m_carPathLinks[k].pos.x == tempnodes[j].pos.x &&
+					   m_carPathLinks[k].pos.y == tempnodes[j].pos.y){
 						m_carPathConnections[m_numConnections] = k;
 						k = m_numCarPathLinks;
 					}
 				}
 				// k is m_numCarPathLinks+1 if we found one
 				if(k == m_numCarPathLinks){
-					m_carPathLinks[m_numCarPathLinks].dirX = tempnodes[j].dirX;
-					m_carPathLinks[m_numCarPathLinks].dirY = tempnodes[j].dirY;
-					m_carPathLinks[m_numCarPathLinks].posX = tempnodes[j].pos.x;
-					m_carPathLinks[m_numCarPathLinks].posY = tempnodes[j].pos.y;
+					m_carPathLinks[m_numCarPathLinks].dir.x = tempnodes[j].dirX;
+					m_carPathLinks[m_numCarPathLinks].dir.y = tempnodes[j].dirY;
+					m_carPathLinks[m_numCarPathLinks].pos.x = tempnodes[j].pos.x;
+					m_carPathLinks[m_numCarPathLinks].pos.y = tempnodes[j].pos.y;
 					m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i;
 					m_carPathLinks[m_numCarPathLinks].numLeftLanes = tempnodes[j].numLeftLanes;
 					m_carPathLinks[m_numCarPathLinks].numRightLanes = tempnodes[j].numRightLanes;
@@ -529,20 +534,20 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor
 					// IMPROVE: use a goto here
 					// Find existing car path link
 					for(k = 0; k < m_numCarPathLinks; k++){
-						if(m_carPathLinks[k].dirX == dx &&
-						   m_carPathLinks[k].dirY == dy &&
-						   m_carPathLinks[k].posX == posx &&
-						   m_carPathLinks[k].posY == posy){
+						if(m_carPathLinks[k].dir.x == dx &&
+						   m_carPathLinks[k].dir.y == dy &&
+						   m_carPathLinks[k].pos.x == posx &&
+						   m_carPathLinks[k].pos.y == posy){
 							m_carPathConnections[m_numConnections] = k;
 							k = m_numCarPathLinks;
 						}
 					}
 					// k is m_numCarPathLinks+1 if we found one
 					if(k == m_numCarPathLinks){
-						m_carPathLinks[m_numCarPathLinks].dirX = dx;
-						m_carPathLinks[m_numCarPathLinks].dirY = dy;
-						m_carPathLinks[m_numCarPathLinks].posX = posx;
-						m_carPathLinks[m_numCarPathLinks].posY = posy;
+						m_carPathLinks[m_numCarPathLinks].dir.x = dx;
+						m_carPathLinks[m_numCarPathLinks].dir.y = dy;
+						m_carPathLinks[m_numCarPathLinks].pos.x = posx;
+						m_carPathLinks[m_numCarPathLinks].pos.y = posy;
 						m_carPathLinks[m_numCarPathLinks].pathNodeIndex = i;
 						m_carPathLinks[m_numCarPathLinks].numLeftLanes = -1;
 						m_carPathLinks[m_numCarPathLinks].numRightLanes = -1;
@@ -760,8 +765,8 @@ CPathFind::SetLinksBridgeLights(float x1, float x2, float y1, float y2, bool ena
 {
 	int i;
 	for(i = 0; i < m_numCarPathLinks; i++)
-		if(x1 < m_carPathLinks[i].posX && m_carPathLinks[i].posX < x2 &&
-		   y1 < m_carPathLinks[i].posY && m_carPathLinks[i].posY < y2)
+		if(x1 < m_carPathLinks[i].pos.x && m_carPathLinks[i].pos.x < x2 &&
+		   y1 < m_carPathLinks[i].pos.y && m_carPathLinks[i].pos.y < y2)
 			m_carPathLinks[i].bBridgeLights = enable;
 }
 
@@ -1444,6 +1449,132 @@ CPathFind::Load(uint8 *buf, uint32 size)
 			m_pathNodes[i].bBetweenLevels = false;
 }
 
+void
+CPathFind::DisplayPathData(void)
+{
+	// Not the function from mobm_carPathLinksile but my own!
+
+	int i, j, k;
+	// Draw 50 units around camera
+	CVector pos = TheCamera.GetPosition();
+	const float maxDist = 50.0f;
+
+	// Render car path nodes
+	if(gbShowCarPaths)
+	for(i = 0; i < m_numCarPathNodes; i++){
+		if((m_pathNodes[i].pos - pos).MagnitudeSqr() > SQR(maxDist))
+			continue;
+
+		CVector n1 = m_pathNodes[i].pos;
+		n1.z += 0.3f;
+
+		// Draw node itself
+		CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+			n1.x, n1.y, n1.z + 1.0f,
+			0xFFFFFFFF, 0xFFFFFFFF);
+
+		for(j = 0; j < m_pathNodes[i].numLinks; j++){
+			k = m_connections[m_pathNodes[i].firstLink + j];
+			CVector n2 = m_pathNodes[k].pos;
+			n2.z += 0.3f;
+			// Draw links to neighbours
+			CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+				n2.x, n2.y, n2.z,
+				0xFFFFFFFF, 0xFFFFFFFF);
+		}
+	}
+
+	// Render car path nodes
+	if(gbShowCarPathsLinks)
+	for(i = 0; i < m_numCarPathLinks; i++){
+		CVector2D n1_2d = m_carPathLinks[i].pos;
+		if((n1_2d - pos).MagnitudeSqr() > SQR(maxDist))
+			continue;
+
+		int ni = m_carPathLinks[i].pathNodeIndex;
+		CVector pn1 = m_pathNodes[ni].pos;
+		pn1.z += 0.3f;
+		CVector n1(n1_2d.x, n1_2d.y, pn1.z);
+		n1.z += 0.3f;
+
+		// Draw car node itself
+		CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+			n1.x, n1.y, n1.z + 1.0f,
+			0xFFFFFFFF, 0xFFFFFFFF);
+		CLines::RenderLineWithClipping(n1.x, n1.y, n1.z + 0.5f,
+			n1.x+m_carPathLinks[i].dir.x, n1.y+m_carPathLinks[i].dir.y, n1.z + 0.5f,
+			0xFFFFFFFF, 0xFFFFFFFF);
+
+		// Draw connection to car path node
+		CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+			pn1.x, pn1.y, pn1.z,
+			0xFF0000FF, 0xFFFFFFFF);
+
+		// traffic light type
+		uint32 col = 0xFF;
+		if((m_carPathLinks[i].trafficLightType&0x7F) == 1)
+			col += 0xFF000000;
+		if((m_carPathLinks[i].trafficLightType&0x7F) == 2)
+			col += 0x00FF0000;
+		if(m_carPathLinks[i].trafficLightType & 0x80)
+			col += 0x0000FF00;
+		CLines::RenderLineWithClipping(n1.x+0.2f, n1.y, n1.z,
+			n1.x+0.2f, n1.y, n1.z + 1.0f,
+			col, col);
+
+		for(j = 0; j < m_pathNodes[ni].numLinks; j++){
+			k = m_carPathConnections[m_pathNodes[ni].firstLink + j];
+			CVector2D n2_2d = m_carPathLinks[k].pos;
+			int nk = m_carPathLinks[k].pathNodeIndex;
+			CVector pn2 = m_pathNodes[nk].pos;
+			pn2.z += 0.3f;
+			CVector n2(n2_2d.x, n2_2d.y, pn2.z);
+			n2.z += 0.3f;
+
+			// Draw links to neighbours
+			CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+				n2.x, n2.y, n2.z,
+				0xFF00FFFF, 0xFF00FFFF);
+		}
+	}
+
+	// Render ped path nodes
+	if(gbShowPedPaths)
+	for(i = m_numCarPathNodes; i < m_numPathNodes; i++){
+		if((m_pathNodes[i].pos - pos).MagnitudeSqr() > SQR(maxDist))
+			continue;
+
+		CVector n1 = m_pathNodes[i].pos;
+		n1.z += 0.3f;
+
+		// Draw node itself
+		CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+			n1.x, n1.y, n1.z + 1.0f,
+			0xFFFFFFFF, 0xFFFFFFFF);
+
+		for(j = 0; j < m_pathNodes[i].numLinks; j++){
+			k = m_connections[m_pathNodes[i].firstLink + j];
+			CVector n2 = m_pathNodes[k].pos;
+			n2.z += 0.3f;
+			// Draw links to neighbours
+			CLines::RenderLineWithClipping(n1.x, n1.y, n1.z,
+				n2.x, n2.y, n2.z,
+				0xFFFFFFFF, 0xFFFFFFFF);
+
+			// Draw connection flags
+			CVector mid = (n1+n2)/2.0f;
+			uint32 col = 0xFF;
+			if(m_connectionFlags[m_pathNodes[i].firstLink + j].bCrossesRoad)
+				col += 0x00FF0000;
+			if(m_connectionFlags[m_pathNodes[i].firstLink + j].bTrafficLight)
+				col += 0xFF000000;
+			CLines::RenderLineWithClipping(mid.x, mid.y, mid.z,
+				mid.x, mid.y, mid.z + 1.0f,
+				col, col);
+		}
+	}
+}
+
 STARTPATCHES
 	InjectHook(0x4294A0, &CPathFind::Init, PATCH_JUMP);
 	InjectHook(0x42D580, &CPathFind::AllocatePathFindInfoMem, PATCH_JUMP);
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index c51cb7c7..81467cdf 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -84,10 +84,8 @@ union CConnectionFlags
 
 struct CCarPathLink
 {
-	float posX;
-	float posY;
-	float dirX;
-	float dirY;
+	CVector2D pos;
+	CVector2D dir;
 	int16 pathNodeIndex;
 	int8 numLeftLanes;
 	int8 numRightLanes;
@@ -208,7 +206,13 @@ public:
 	bool TestCoorsCloseness(CVector target, uint8 type, CVector start);
 	void Save(uint8 *buf, uint32 *size);
 	void Load(uint8 *buf, uint32 size);
+
+	void DisplayPathData(void);
 };
 static_assert(sizeof(CPathFind) == 0x49bf4, "CPathFind: error");
 
 extern CPathFind &ThePaths;
+
+extern bool gbShowPedPaths;
+extern bool gbShowCarPaths;
+extern bool gbShowCarPathsLinks;
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp
index 3e3c2a48..eb561670 100644
--- a/src/control/Pickups.cpp
+++ b/src/control/Pickups.cpp
@@ -1,1049 +1,1452 @@
-#include "common.h"
-#include "patcher.h"
-#include "main.h"
-
-#include "Camera.h"
-#include "Coronas.h"
-#include "Darkel.h"
-#include "Entity.h"
-#include "Explosion.h"
-#include "Font.h"
-#include "Garages.h"
-#include "General.h"
-#include "ModelIndices.h"
-#include "Object.h"
-#include "Pad.h"
-#include "Pickups.h"
-#include "PlayerPed.h"
-#include "Wanted.h"
-#include "DMAudio.h"
-#include "Fire.h"
-#include "PointLights.h"
-#include "Pools.h"
-#ifdef FIX_BUGS
-#include "Replay.h"
-#endif
-#include "Script.h"
-#include "Shadows.h"
-#include "SpecialFX.h"
-#include "Sprite.h"
-#include "Timer.h"
-#include "WaterLevel.h"
-#include "World.h"
-
-CPickup(&CPickups::aPickUps)[NUMPICKUPS] = *(CPickup(*)[NUMPICKUPS])*(uintptr*)0x878C98;
-int16 CPickups::NumMessages;// = *(int16*)0x95CC98;
-int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];// = *(int32(*)[NUMCOLLECTEDPICKUPS])*(uintptr*)0x87C538;
-int16 CPickups::CollectedPickUpIndex;// = *(int16*)0x95CC8A;
-
-// unused
-bool &CPickups::bPickUpcamActivated = *(bool*)0x95CD71;
-CVehicle *&CPickups::pPlayerVehicle = *(CVehicle**)0x8F29E8;
-CVector &CPickups::StaticCamCoors = *(CVector*)0x9404C8;
-uint32 &CPickups::StaticCamStartTime = *(uint32*)0x8E289C;
-
-tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES];
-
-// 20 ?! Some Miami leftover? (Originally at 0x5ED8D4)
-uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 };
-uint16 AmmoForWeapon_OnStreet[20] = { 0, 1, 9, 25, 5, 30, 60, 5, 1, 50, 1, 1, 0, 200, 0, 100, 0, 0, 0, 0 };
-uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 };
-
-uint8 aWeaponReds[] = { 255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, 255, 128, 0, 255, 0 };
-uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 255, 0, 255, 0 };
-uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 };
-float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f };
-
-WRAPPER void CPacManPickups::Init(void) { EAXJMP(0x432760); }
-WRAPPER void CPacManPickups::Update(void) { EAXJMP(0x432800); }
-WRAPPER void CPacManPickups::GeneratePMPickUps(CVector, float, int16, uint8) { EAXJMP(0x432AE0); }
-WRAPPER void CPacManPickups::GeneratePMPickUpsForRace(int32) { EAXJMP(0x432D50); }
-WRAPPER void CPacManPickups::GenerateOnePMPickUp(CVector) { EAXJMP(0x432F20); }
-WRAPPER void CPacManPickups::Render(void) { EAXJMP(0x432F60); }
-WRAPPER void CPacManPickups::DoCleanUpPacManStuff(void) { EAXJMP(0x433150); }
-WRAPPER void CPacManPickups::StartPacManRace(int32) { EAXJMP(0x433340); }
-WRAPPER void CPacManPickups::StartPacManRecord(void) { EAXJMP(0x433360); }
-WRAPPER uint32 CPacManPickups::QueryPowerPillsEatenInRace(void) { EAXJMP(0x4333A0); }
-WRAPPER void CPacManPickups::ResetPowerPillsEatenInRace(void) { EAXJMP(0x4333B0); }
-WRAPPER void CPacManPickups::CleanUpPacManStuff(void) { EAXJMP(0x4333C0); }
-WRAPPER void CPacManPickups::StartPacManScramble(CVector, float, int16) { EAXJMP(0x4333D0); }
-WRAPPER uint32 CPacManPickups::QueryPowerPillsCarriedByPlayer(void) { EAXJMP(0x4333F0); }
-WRAPPER void CPacManPickups::ResetPowerPillsCarriedByPlayer(void) { EAXJMP(0x433410); }
-
-
-void
-CPickup::RemoveKeepType()
-{
-	CWorld::Remove(m_pObject);
-	delete m_pObject;
-
-	m_bRemoved = true;
-	m_pObject = nil;
-}
-
-void
-CPickup::Remove()
-{
-	RemoveKeepType();
-	m_eType = PICKUP_NONE;
-}
-
-CObject *
-CPickup::GiveUsAPickUpObject(int32 handle)
-{
-	CObject *object;
-
-	if (handle <= 0) object = new CObject(m_eModelIndex, false);
-	else {
-		CPools::MakeSureSlotInObjectPoolIsEmpty(handle);
-		object = new(handle) CObject(m_eModelIndex, false);
-	}
-
-	if (object == nil) return nil;
-	object->ObjectCreatedBy = MISSION_OBJECT;
-	object->GetPosition() = m_vecPos;
-	object->SetOrientation(0.0f, 0.0f, -HALFPI);
-	object->GetMatrix().UpdateRW();
-	object->UpdateRwFrame();
-
-	object->bAffectedByGravity = false;
-	object->bExplosionProof = true;
-	object->bUsesCollision = false;
-	object->bIsPickup = true;
-
-	object->field_172 = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0;
-
-	switch (m_eType)
-	{
-	case PICKUP_IN_SHOP:
-		object->m_obj_flag2 = true;
-		object->bOutOfStock = false;
-		break;
-	case PICKUP_ON_STREET:
-	case PICKUP_ONCE:
-	case PICKUP_ONCE_TIMEOUT:
-	case PICKUP_COLLECTABLE1:
-	case PICKUP_MONEY:
-	case PICKUP_MINE_INACTIVE:
-	case PICKUP_MINE_ARMED:
-	case PICKUP_NAUTICAL_MINE_INACTIVE:
-	case PICKUP_NAUTICAL_MINE_ARMED:
-	case PICKUP_FLOATINGPACKAGE:
-	case PICKUP_ON_STREET_SLOW:
-		object->m_obj_flag2 = false;
-		object->bOutOfStock = false;
-		break;
-	case PICKUP_IN_SHOP_OUT_OF_STOCK:
-		object->m_obj_flag2 = false;
-		object->bOutOfStock = true;
-		object->bRenderScorched = true;
-		break;
-	case PICKUP_FLOATINGPACKAGE_FLOATING:
-	default:
-		break;
-	}
-	return object;
-}
-
-bool
-CPickup::CanBePickedUp(CPlayerPed *player)
-{
-	assert(m_pObject != nil);
-	bool cannotBePickedUp =
-		(m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f)
-		|| (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f)
-		|| (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0)
-		|| (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame));
-	return !cannotBePickedUp;
-}
-
-bool
-CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
-{
-	float waterLevel;
-
-	if (m_bRemoved) {
-		if (CTimer::GetTimeInMilliseconds() > m_nTimer) {
-			// respawn pickup if we're far enough
-			float dist = (FindPlayerCoors().x - m_vecPos.x) * (FindPlayerCoors().x - m_vecPos.x) + (FindPlayerCoors().y - m_vecPos.y) * (FindPlayerCoors().y - m_vecPos.y);
-			if (dist > 100.0f || m_eType == PICKUP_IN_SHOP && dist > 2.4f) {
-				m_pObject = GiveUsAPickUpObject(-1);
-				if (m_pObject) {
-					CWorld::Add(m_pObject);
-					m_bRemoved = false;
-				}
-			}
-		}
-		return false;
-	}
-
-	if (!m_pObject) return false;
-
-	if (!IsMine()) {
-		// let's check if we touched the pickup
-		bool isPickupTouched = false;
-		if (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE) {
-			if (vehicle != nil) {
-				if (vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f))
-					isPickupTouched = true;
-			}
-			else {
-				if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
-					if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
-						(player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
-						isPickupTouched = true;
-				}
-			}
-		} else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA) {
-			if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
-				isPickupTouched = true;
-			}
-		} else if (vehicle == nil) {
-			if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
-				if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
-					(player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
-					isPickupTouched = true;
-			}
-		}
-
-		// if we didn't then we've got nothing to do
-		if (isPickupTouched && CanBePickedUp(player)) {
-			CPad::GetPad(0)->StartShake(120, 100);
-			switch (m_eType)
-			{
-			case PICKUP_IN_SHOP:
-				if (CWorld::Players[playerId].m_nMoney < CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]) {
-					CGarages::TriggerMessage("PU_MONY", -1, 6000, -1);
-				} else {
-					CWorld::Players[playerId].m_nMoney -= CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())];
-					if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
-						player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
-						player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
-						DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON_BOUGHT, m_pObject->GetModelIndex() - MI_GRENADE);
-					}
-					RemoveKeepType();
-					m_nTimer = CTimer::GetTimeInMilliseconds() + 5000;
-					return true;
-				}
-				break;
-			case PICKUP_ON_STREET:
-			case PICKUP_ON_STREET_SLOW:
-				if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
-					if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
-						player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon_OnStreet[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
-						if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED)) {
-							player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
-						}
-						DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
-					} else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA && vehicle != nil) {
-						DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
-						CPickups::bPickUpcamActivated = true;
-						CPickups::pPlayerVehicle = FindPlayerVehicle();
-						CPickups::StaticCamCoors = m_pObject->GetPosition();
-						CPickups::StaticCamStartTime = CTimer::GetTimeInMilliseconds();
-					}
-				}
-				if (m_eType == PICKUP_ON_STREET) {
-					m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
-				} else if (m_eType == PICKUP_ON_STREET_SLOW) {
-					if (MI_PICKUP_BRIBE == m_pObject->m_modelIndex)
-						m_nTimer = CTimer::GetTimeInMilliseconds() + 300000;
-					else
-						m_nTimer = CTimer::GetTimeInMilliseconds() + 720000;
-				}
-
-				RemoveKeepType();
-				return true;
-			case PICKUP_ONCE:
-			case PICKUP_ONCE_TIMEOUT:
-				if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
-					if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
-						player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
-						if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED))
-							player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
-					}
-					DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
-				}
-				Remove();
-				return true;
-			case PICKUP_COLLECTABLE1:
-				CWorld::Players[playerId].m_nCollectedPackages++;
-				CWorld::Players[playerId].m_nMoney += 1000;
-
-				if (CWorld::Players[playerId].m_nCollectedPackages == CWorld::Players[playerId].m_nTotalPackages) {
-					printf("All collectables have been picked up\n");
-					CGarages::TriggerMessage("CO_ALL", -1, 5000, -1);
-					CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1000000;
-				} else
-					CGarages::TriggerMessage("CO_ONE", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 5000, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
-
-				Remove();
-				DMAudio.PlayFrontEndSound(SOUND_PICKUP_HIDDEN_PACKAGE, 0);
-				return true;
-			case PICKUP_MONEY:
-				CWorld::Players[playerId].m_nMoney += m_nQuantity;
-				sprintf(gString, "$%d", m_nQuantity);
-#ifdef MONEY_MESSAGES
-				CMoneyMessages::RegisterOne(m_vecPos + CVector(0.0f, 0.0f, 1.0f), gString, 0, 255, 0, 0.5f, 0.5f);
-#endif
-				Remove();
-				DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
-				return true;
-			//case PICKUP_IN_SHOP_OUT_OF_STOCK:
-			//case PICKUP_MINE_INACTIVE:
-			//case PICKUP_MINE_ARMED:
-			//case PICKUP_NAUTICAL_MINE_INACTIVE:
-			//case PICKUP_NAUTICAL_MINE_ARMED:
-			//case PICKUP_FLOATINGPACKAGE:
-			//case PICKUP_FLOATINGPACKAGE_FLOATING:
-			default:
-				break;
-			}
-		}
-	} else {
-		switch (m_eType)
-		{
-		case PICKUP_MINE_INACTIVE:
-			if (vehicle != nil && !vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
-				m_eType = PICKUP_MINE_ARMED;
-				m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
-			}
-			break;
-		case PICKUP_NAUTICAL_MINE_INACTIVE:
-		{
-			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
-				m_pObject->GetPosition().z = waterLevel + 0.6f;
-
-			m_pObject->GetMatrix().UpdateRW();
-			m_pObject->UpdateRwFrame();
-
-			bool touched = false;
-			for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
-				CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
-				if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
-					touched = true;
-					break; // added break here
-				}
-			}
-
-			if (!touched) {
-				m_eType = PICKUP_NAUTICAL_MINE_ARMED;
-				m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
-			}
-			break;
-		}
-		case PICKUP_NAUTICAL_MINE_ARMED:
-			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
-				m_pObject->GetPosition().z = waterLevel + 0.6f;
-
-			m_pObject->GetMatrix().UpdateRW();
-			m_pObject->UpdateRwFrame();
-			// no break here
-		case PICKUP_MINE_ARMED:
-		{
-			bool explode = false;
-			if (CTimer::GetTimeInMilliseconds() > m_nTimer)
-				explode = true;
-			else {// added else here since vehicle lookup is useless
-				for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
-					CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
-					if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
-						explode = true;
-						break; // added break here
-					}
-				}
-			}
-			if (explode) {
-				CExplosion::AddExplosion(nil, nil, EXPLOSION_MINE, m_pObject->GetPosition(), 0);
-				Remove();
-			}
-			break;
-		}
-		case PICKUP_FLOATINGPACKAGE:
-			m_pObject->m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep();
-			m_pObject->GetPosition() += m_pObject->GetMoveSpeed() * CTimer::GetTimeStep();
-
-			m_pObject->GetMatrix().UpdateRW();
-			m_pObject->UpdateRwFrame();
-			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z)
-				m_eType = PICKUP_FLOATINGPACKAGE_FLOATING;
-			break;
-		case PICKUP_FLOATINGPACKAGE_FLOATING:
-			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0))
-				m_pObject->GetPosition().z = waterLevel;
-
-			m_pObject->GetMatrix().UpdateRW();
-			m_pObject->UpdateRwFrame();
-			if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
-				Remove();
-				DMAudio.PlayFrontEndSound(SOUND_PICKUP_FLOAT_PACKAGE, 0);
-				return true;
-			}
-			break;
-		}
-	}
-	if (!m_bRemoved && (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_MONEY) && CTimer::GetTimeInMilliseconds() > m_nTimer)
-		Remove();
-	return false;
-}
-
-void
-CPickups::Init(void)
-{
-	NumMessages = 0;
-	for (int i = 0; i < NUMPICKUPS; i++) {
-		aPickUps[i].m_eType = PICKUP_NONE;
-		aPickUps[i].m_nIndex = 1;
-		aPickUps[i].m_pObject = nil;
-	}
-
-	for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++)
-		aPickUpsCollected[i] = 0;
-
-	CollectedPickUpIndex = 0;
-}
-
-bool
-CPickups::IsPickUpPickedUp(int32 pickupId)
-{
-	for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++) {
-		if (pickupId == aPickUpsCollected[i]) {
-			aPickUpsCollected[i] = 0;
-			return true;
-		}
-	}
-	return false;
-}
-
-void
-CPickups::PassTime(uint32 time)
-{
-	for (int i = 0; i < NUMPICKUPS; i++) {
-		if (aPickUps[i].m_eType != PICKUP_NONE) {
-			if (aPickUps[i].m_nTimer <= time)
-				aPickUps[i].m_nTimer = 0;
-			else
-				aPickUps[i].m_nTimer -= time;
-		}
-	}
-}
-
-int32
-CPickups::GetActualPickupIndex(int32 index)
-{
-	if (index == -1) return -1;
-
-	// doesn't look nice
-	if ((uint16)((index & 0xFFFF0000) >> 16) != aPickUps[(uint16)index].m_nIndex) return -1;
-	return (uint16)index;
-}
-
-bool
-CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
-{
-	CPlayerPed *player;
-
-	if (playerIndex <= 0) player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
-	else player = CWorld::Players[playerIndex].m_pPed;
-
-	if (modelIndex == MI_PICKUP_ADRENALINE) {
-		player->m_bAdrenalineActive = true;
-		player->m_nAdrenalineTime = CTimer::GetTimeInMilliseconds() + 20000;
-		player->m_fCurrentStamina = player->m_fMaxStamina;
-		DMAudio.PlayFrontEndSound(SOUND_PICKUP_ADRENALINE, 0);
-		return true;
-	} else if (modelIndex == MI_PICKUP_BODYARMOUR) {
-		player->m_fArmour = 100.0f;
-		DMAudio.PlayFrontEndSound(SOUND_PICKUP_ARMOUR, 0);
-		return true;
-	} else if (modelIndex == MI_PICKUP_INFO) {
-		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
-		return true;
-	} else if (modelIndex == MI_PICKUP_HEALTH) {
-		player->m_fHealth = 100.0f;
-		DMAudio.PlayFrontEndSound(SOUND_PICKUP_HEALTH, 0);
-		return true;
-	} else if (modelIndex == MI_PICKUP_BONUS) {
-		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
-		return true;
-	} else if (modelIndex == MI_PICKUP_BRIBE) {
-		int32 level = FindPlayerPed()->m_pWanted->m_nWantedLevel - 1;
-		if (level < 0) level = 0;
-		player->SetWantedLevel(level);
-		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
-		return true;
-	} else if (modelIndex == MI_PICKUP_KILLFRENZY) {
-		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
-		return true;
-	}
-	return false;
-}
-
-void
-CPickups::RemoveAllFloatingPickups()
-{
-	for (int i = 0; i < NUMPICKUPS; i++) {
-		if (aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE || aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE_FLOATING) {
-			if (aPickUps[i].m_pObject) {
-				CWorld::Remove(aPickUps[i].m_pObject);
-				delete aPickUps[i].m_pObject;
-				aPickUps[i].m_pObject = nil;
-			}
-		}
-	}
-}
-
-void
-CPickups::RemovePickUp(int32 pickupIndex)
-{
-	int32 index = CPickups::GetActualPickupIndex(pickupIndex);
-	if (index == -1) return;
-
-	if (aPickUps[index].m_pObject) {
-		CWorld::Remove(aPickUps[index].m_pObject);
-		delete aPickUps[index].m_pObject;
-		aPickUps[index].m_pObject = nil;
-	}
-	aPickUps[index].m_eType = PICKUP_NONE;
-	aPickUps[index].m_bRemoved = true;
-}
-
-int32
-CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity)
-{
-	bool bFreeFound = false;
-	int32 slot = 0;
-
-	if (type == PICKUP_FLOATINGPACKAGE || type == PICKUP_NAUTICAL_MINE_INACTIVE) {
-		for (slot = NUMPICKUPS; slot >= 0; slot--) {
-			if (aPickUps[slot].m_eType == PICKUP_NONE) {
-				bFreeFound = true;
-				break;
-			}
-		}
-	} else {
-		for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
-			if (aPickUps[slot].m_eType == PICKUP_NONE) {
-				bFreeFound = true;
-				break;
-			}
-		}
-	}
-
-	if (!bFreeFound)
-	{
-		for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
-			if (aPickUps[slot].m_eType == PICKUP_MONEY) break;
-		}
-
-		if (slot >= NUMGENERALPICKUPS)
-		{
-			for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
-				if (aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT) break;
-			}
-
-			if (slot >= NUMGENERALPICKUPS) return -1;
-		}
-	}
-
-	if (slot >= NUMPICKUPS) return -1;
-
-	aPickUps[slot].m_eType = (ePickupType)type;
-	aPickUps[slot].m_bRemoved = false;
-	aPickUps[slot].m_nQuantity = quantity;
-	if (type == PICKUP_ONCE_TIMEOUT)
-		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000;
-	else if (type == PICKUP_MONEY)
-		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
-	else if (type == PICKUP_MINE_INACTIVE || type == PICKUP_MINE_ARMED) {
-		aPickUps[slot].m_eType = PICKUP_MINE_INACTIVE;
-		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
-	} else if (type == PICKUP_NAUTICAL_MINE_INACTIVE || type == PICKUP_NAUTICAL_MINE_ARMED) {
-		aPickUps[slot].m_eType = PICKUP_NAUTICAL_MINE_INACTIVE;
-		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
-	}
-	aPickUps[slot].m_eModelIndex = modelIndex;
-	aPickUps[slot].m_vecPos = pos;
-	aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(-1);
-	if (aPickUps[slot].m_pObject)
-		CWorld::Add(aPickUps[slot].m_pObject);
-	return GetNewUniquePickupIndex(slot);
-}
-
-int32
-CPickups::GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity)
-{
-	return GenerateNewOne(pos, ModelForWeapon(weaponType), type, quantity);
-}
-
-int32
-CPickups::GetNewUniquePickupIndex(int32 slot)
-{
-	if (aPickUps[slot].m_nIndex >= 0xFFFE)
-		aPickUps[slot].m_nIndex = 1;
-	else
-		aPickUps[slot].m_nIndex++;
-	return slot | (aPickUps[slot].m_nIndex << 16);
-}
-
-int32
-CPickups::ModelForWeapon(eWeaponType weaponType)
-{
-	switch (weaponType)
-	{
-	case WEAPONTYPE_BASEBALLBAT: return MI_BASEBALL_BAT;
-	case WEAPONTYPE_COLT45: return MI_COLT;
-	case WEAPONTYPE_UZI: return MI_UZI;
-	case WEAPONTYPE_SHOTGUN: return MI_SHOTGUN;
-	case WEAPONTYPE_AK47: return MI_AK47;
-	case WEAPONTYPE_M16: return MI_M16;
-	case WEAPONTYPE_SNIPERRIFLE: return MI_SNIPER;
-	case WEAPONTYPE_ROCKETLAUNCHER: return MI_ROCKETLAUNCHER;
-	case WEAPONTYPE_FLAMETHROWER: return MI_FLAMETHROWER;
-	case WEAPONTYPE_MOLOTOV: return MI_MOLOTOV;
-	case WEAPONTYPE_GRENADE: return MI_GRENADE;
-	}
-	return 0;
-}
-
-eWeaponType
-CPickups::WeaponForModel(int32 model)
-{
-	if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR;
-	switch (model)
-	{
-	case MI_GRENADE: return WEAPONTYPE_GRENADE;
-	case MI_AK47: return WEAPONTYPE_AK47;
-	case MI_BASEBALL_BAT: return WEAPONTYPE_BASEBALLBAT;
-	case MI_COLT: return WEAPONTYPE_COLT45;
-	case MI_MOLOTOV: return WEAPONTYPE_MOLOTOV;
-	case MI_ROCKETLAUNCHER: return WEAPONTYPE_ROCKETLAUNCHER;
-	case MI_SHOTGUN: return WEAPONTYPE_SHOTGUN;
-	case MI_SNIPER: return WEAPONTYPE_SNIPERRIFLE;
-	case MI_UZI: return WEAPONTYPE_UZI;
-	case MI_MISSILE: return WEAPONTYPE_UNARMED;
-	case MI_M16: return WEAPONTYPE_M16;
-	case MI_FLAMETHROWER: return WEAPONTYPE_FLAMETHROWER;
-	}
-	return WEAPONTYPE_UNARMED;
-}
-
-int32
-CPickups::FindColourIndexForWeaponMI(int32 model)
-{
-	return WeaponForModel(model) - 1;
-}
-
-void
-CPickups::AddToCollectedPickupsArray(int32 index)
-{
-	aPickUpsCollected[CollectedPickUpIndex++] = index | (aPickUps[index].m_nIndex << 16);
-	if (CollectedPickUpIndex >= NUMCOLLECTEDPICKUPS)
-		CollectedPickUpIndex = 0;
-}
-
-void
-CPickups::Update()
-{
-#ifdef FIX_BUGS // RIP speedrunning (solution from SA)
-	if (CReplay::IsPlayingBack())
-		return;
-#endif
-#define PICKUPS_FRAME_SPAN (6)
-#ifdef FIX_BUGS
-	for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) {
-#else // BUG: this code can only reach 318 out of 320 pickups
-	for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
-#endif
-		if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
-			AddToCollectedPickupsArray(i);
-		}
-	}
-#undef PICKUPS_FRAME_SPAN
-	for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
-		if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
-			AddToCollectedPickupsArray(i);
-		}
-	}
-}
-
-void
-CPickups::DoPickUpEffects(CEntity *entity)
-{
-	if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
-		entity->m_flagD80 = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame;
-
-	if (!entity->m_flagD80) {
-		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
-		float modifiedSin = 0.3f * (s + 1.0f);
-
-
-		int16 colorId;
-
-		if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA)
-			colorId = 11;
-		else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR || entity->GetModelIndex() == MI_PICKUP_BRIBE)
-			colorId = 12;
-		else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
-			colorId = 13;
-		else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS)
-			colorId = 14;
-		else
-			colorId = FindColourIndexForWeaponMI(entity->GetModelIndex());
-
-		assert(colorId >= 0);
-
-		CVector &pos = entity->GetPosition();
-
-		float colorModifier = ((CGeneral::GetRandomNumber() & 0x1F) * 0.015f + 1.0f) * modifiedSin * 0.15f;
-		CShadows::StoreStaticShadow(
-			(uintptr)entity,
-			SHADOWTYPE_ADDITIVE,
-			gpShadowExplosionTex,
-			&pos,
-			2.0f, 0.0f, 0.0f, -2.0f,
-			255,                                        // this is 0 on PC which results in no shadow
-			aWeaponReds[colorId] * colorModifier, aWeaponGreens[colorId] * colorModifier, aWeaponBlues[colorId] * colorModifier,
-			4.0f, 1.0f, 40.0f, false, 0.0f);
-
-		float radius = (CGeneral::GetRandomNumber() & 0xF) * 0.1f + 3.0f;
-		CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f), radius, aWeaponReds[colorId] * modifiedSin / 256.0f, aWeaponGreens[colorId] * modifiedSin / 256.0f, aWeaponBlues[colorId] * modifiedSin / 256.0f, CPointLights::FOG_NONE, true);
-		float size = (CGeneral::GetRandomNumber() & 0xF) * 0.0005f + 0.6f;
-		CCoronas::RegisterCorona( (uintptr)entity,
-			aWeaponReds[colorId] * modifiedSin / 2.0f, aWeaponGreens[colorId] * modifiedSin / 2.0f, aWeaponBlues[colorId] * modifiedSin / 2.0f,
-			255,
-			pos,
-			size, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
-
-		CObject *object = (CObject*)entity;
-		if (object->m_obj_flag2 || object->bOutOfStock || object->field_172) {
-			float dist = (TheCamera.GetPosition() - pos).Magnitude();
-			const float MAXDIST = 12.0f;
-
-			if (dist < MAXDIST && NumMessages < NUMPICKUPMESSAGES) {
-				RwV3d vecOut;
-				float fDistX, fDistY;
-				if (CSprite::CalcScreenCoors(entity->GetPosition() + CVector(0.0f, 0.0f, 0.7f), &vecOut, &fDistX, &fDistY, true)) {
-					aMessages[NumMessages].m_pos.x = vecOut.x;
-					aMessages[NumMessages].m_pos.y = vecOut.y;
-					aMessages[NumMessages].m_dist.x = fDistX;
-					aMessages[NumMessages].m_dist.y = fDistY;
-					aMessages[NumMessages].m_weaponType = WeaponForModel(entity->GetModelIndex());
-					aMessages[NumMessages].m_color.red = aWeaponReds[colorId];
-					aMessages[NumMessages].m_color.green = aWeaponGreens[colorId];
-					aMessages[NumMessages].m_color.blue = aWeaponBlues[colorId];
-					aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f;
-					aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock;
-					aMessages[NumMessages].m_quantity = object->field_172;
-					NumMessages++;
-				}
-			}
-		}
-
-		entity->GetMatrix().SetRotateZOnlyScaled((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800), aWeaponScale[colorId]);
-	}
-}
-
-void
-CPickups::DoMineEffects(CEntity *entity)
-{
-	CVector &pos = entity->GetPosition();
-	float dist = (TheCamera.GetPosition() - pos).Magnitude();
-	const float MAXDIST = 20.0f;
-
-	if (dist < MAXDIST) {
-		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x1FF) * DEGTORAD(360.0f / 0x200));
-
-		int32 red = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 64.0f;
-		CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
-			2.0f, 0.0f, 0.0f, -2.0f,
-			255,                                        // this is 0 on PC which results in no shadow
-			red, 0, 0,
-			4.0f, 1.0f, 40.0f, false, 0.0f);
-		CCoronas::RegisterCorona((uintptr)entity, red, 0, 0, 255, pos, 0.6f, 60.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
-	}
-
-	entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x3FF) * DEGTORAD(360.0f / 0x400));
-}
-
-void
-CPickups::DoMoneyEffects(CEntity *entity)
-{
-	CVector &pos = entity->GetPosition();
-	float dist = (TheCamera.GetPosition() - pos).Magnitude();
-	const float MAXDIST = 20.0f;
-
-	if (dist < MAXDIST) {
-		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x3FF) * DEGTORAD(360.0f / 0x400));
-
-		int32 green = (MAXDIST - dist) * (0.2f * s + 0.3f) / MAXDIST * 64.0f;
-		CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
-			2.0f, 0.0f, 0.0f, -2.0f,
-			255,                                        // this is 0 on PC which results in no shadow
-			0, green, 0,
-			4.0f, 1.0f, 40.0f, false, 0.0f);
-		CCoronas::RegisterCorona((uintptr)entity, 0, green, 0, 255, pos, 0.4f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
-	}
-
-	entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800));
-}
-
-void
-CPickups::DoCollectableEffects(CEntity *entity)
-{
-	CVector &pos = entity->GetPosition();
-	float dist = (TheCamera.GetPosition() - pos).Magnitude();
-	const float MAXDIST = 14.0f;
-
-	if (dist < MAXDIST) {
-		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
-
-		int32 color = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 255.0f;
-		CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
-			2.0f, 0.0f, 0.0f, -2.0f,
-			255,                                        // this is 0 on PC which results in no shadow
-			color, color, color,
-			4.0f, 1.0f, 40.0f, false, 0.0f);
-		CCoronas::RegisterCorona((uintptr)entity, color, color, color, 255, pos, 0.6f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
-	}
-
-	entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0xFFF) * DEGTORAD(360.0f / 0x1000));
-}
-
-void
-CPickups::RenderPickUpText()
-{
-	wchar *strToPrint;
-	for (int32 i = 0; i < NumMessages; i++) {
-		if (aMessages[i].m_quantity <= 39) {
-			switch (aMessages[i].m_quantity) // could use some enum maybe
-			{
-			case 0:
-				if (aMessages[i].m_weaponType == WEAPONTYPE_TOTALWEAPONS) { // unreachable code?
-					// what is this??
-					sprintf(gString, "%d/%d", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 2903);
-				} else {
-					if (aMessages[i].m_bOutOfStock)
-						strToPrint = TheText.Get("STOCK");
-					else {
-						sprintf(gString, "$%d", CostOfWeapon[aMessages[i].m_weaponType]);
-						AsciiToUnicode(gString, gUString);
-						strToPrint = gUString;
-					}
-				}
-				break;
-			case 1:
-				strToPrint = TheText.Get("SECURI");
-				break;
-			case 2:
-				strToPrint = TheText.Get("MOONBM");
-				break;
-			case 3:
-				strToPrint = TheText.Get("COACH");
-				break;
-			case 4:
-				strToPrint = TheText.Get("FLATBED");
-				break;
-			case 5:
-				strToPrint = TheText.Get("LINERUN");
-				break;
-			case 6:
-				strToPrint = TheText.Get("TRASHM");
-				break;
-			case 7:
-				strToPrint = TheText.Get("PATRIOT");
-				break;
-			case 8:
-				strToPrint = TheText.Get("WHOOPEE");
-				break;
-			case 9:
-				strToPrint = TheText.Get("BLISTA");
-				break;
-			case 10:
-				strToPrint = TheText.Get("MULE");
-				break;
-			case 11:
-				strToPrint = TheText.Get("YANKEE");
-				break;
-			case 12:
-				strToPrint = TheText.Get("BOBCAT");
-				break;
-			case 13:
-				strToPrint = TheText.Get("DODO");
-				break;
-			case 14:
-				strToPrint = TheText.Get("BUS");
-				break;
-			case 15:
-				strToPrint = TheText.Get("RUMPO");
-				break;
-			case 16:
-				strToPrint = TheText.Get("PONY");
-				break;
-			case 17:
-				strToPrint = TheText.Get("SENTINL");
-				break;
-			case 18:
-				strToPrint = TheText.Get("CHEETAH");
-				break;
-			case 19:
-				strToPrint = TheText.Get("BANSHEE");
-				break;
-			case 20:
-				strToPrint = TheText.Get("IDAHO");
-				break;
-			case 21:
-				strToPrint = TheText.Get("INFERNS");
-				break;
-			case 22:
-				strToPrint = TheText.Get("TAXI");
-				break;
-			case 23:
-				strToPrint = TheText.Get("KURUMA");
-				break;
-			case 24:
-				strToPrint = TheText.Get("STRETCH");
-				break;
-			case 25:
-				strToPrint = TheText.Get("PEREN");
-				break;
-			case 26:
-				strToPrint = TheText.Get("STINGER");
-				break;
-			case 27:
-				strToPrint = TheText.Get("MANANA");
-				break;
-			case 28:
-				strToPrint = TheText.Get("LANDSTK");
-				break;
-			case 29:
-				strToPrint = TheText.Get("STALION");
-				break;
-			case 30:
-				strToPrint = TheText.Get("BFINJC");
-				break;
-			case 31:
-				strToPrint = TheText.Get("CABBIE");
-				break;
-			case 32:
-				strToPrint = TheText.Get("ESPERAN");
-				break;
-			case 33:
-				strToPrint = TheText.Get("FIRETRK");
-				break;
-			case 34:
-				strToPrint = TheText.Get("AMBULAN");
-				break;
-			case 35:
-				strToPrint = TheText.Get("ENFORCR");
-				break;
-			case 36:
-				strToPrint = TheText.Get("FBICAR");
-				break;
-			case 37:
-				strToPrint = TheText.Get("RHINO");
-				break;
-			case 38:
-				strToPrint = TheText.Get("BARRCKS");
-				break;
-			case 39:
-				strToPrint = TheText.Get("POLICAR");
-				break;
-			default:
-				break;
-			}
-		}
-		CFont::SetPropOn();
-		CFont::SetBackgroundOff();
-
-		const float MAX_SCALE = 1.0f;
-
-		float fScaleY = aMessages[i].m_dist.y / 100.0f;
-		if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE;
-
-		float fScaleX = aMessages[i].m_dist.x / 100.0f;
-		if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE;
-
-		CFont::SetScale(fScaleX, fScaleY);
-		CFont::SetCentreOn();
-		CFont::SetCentreSize(SCREEN_WIDTH);
-		CFont::SetJustifyOff();
-
-		CFont::SetColor(CRGBA(aMessages[i].m_color.red, aMessages[i].m_color.green, aMessages[i].m_color.blue, aMessages[i].m_color.alpha));
-		CFont::SetBackGroundOnlyTextOff();
-		CFont::SetFontStyle(FONT_BANK);
-		CFont::PrintString(aMessages[i].m_pos.x, aMessages[i].m_pos.y, strToPrint);
-	}
-	NumMessages = 0;
-}
-
-void
-CPickups::Load(uint8 *buf, uint32 size)
-{
-INITSAVEBUF
-
-	for (int32 i = 0; i < NUMPICKUPS; i++) {
-		aPickUps[i] = ReadSaveBuf<CPickup>(buf);
-
-		if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil)
-			aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((int32)aPickUps[i].m_pObject - 1);
-	}
-
-	CollectedPickUpIndex = ReadSaveBuf<uint16>(buf);
-	ReadSaveBuf<uint16>(buf);
-	NumMessages = 0;
-
-	for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
-		aPickUpsCollected[i] = ReadSaveBuf<int32>(buf);
-
-VALIDATESAVEBUF(size)
-}
-
-void
-CPickups::Save(uint8 *buf, uint32 *size)
-{
-	*size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected);
-
-INITSAVEBUF
-
-	for (int32 i = 0; i < NUMPICKUPS; i++) {
-		CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]);
-		if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil)
-			buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1);
-	}
-
-	WriteSaveBuf(buf, CollectedPickUpIndex);
-	WriteSaveBuf(buf, (uint16)0); // possibly was NumMessages
-
-	for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
-		WriteSaveBuf(buf, aPickUpsCollected[i]);
-
-VALIDATESAVEBUF(*size)
-}
-
-STARTPATCHES
-	InjectHook(0x430220, CPickups::Init, PATCH_JUMP);
-	InjectHook(0x4303D0, CPickups::Update, PATCH_JUMP);
-	InjectHook(0x432440, CPickups::RenderPickUpText, PATCH_JUMP);
-	InjectHook(0x431C30, CPickups::DoCollectableEffects, PATCH_JUMP);
-	InjectHook(0x431F40, CPickups::DoMoneyEffects, PATCH_JUMP);
-	InjectHook(0x4321C0, CPickups::DoMineEffects, PATCH_JUMP);
-	InjectHook(0x431520, CPickups::DoPickUpEffects, PATCH_JUMP);
-	InjectHook(0x4304B0, CPickups::GenerateNewOne, PATCH_JUMP);
-	InjectHook(0x430660, CPickups::GenerateNewOne_WeaponType, PATCH_JUMP);
-	InjectHook(0x4307A0, CPickups::RemovePickUp, PATCH_JUMP);
-	InjectHook(0x430800, CPickups::RemoveAllFloatingPickups, PATCH_JUMP);
-	InjectHook(0x433D60, CPickups::AddToCollectedPickupsArray, PATCH_JUMP);
-	InjectHook(0x430770, CPickups::IsPickUpPickedUp, PATCH_JUMP);
-	InjectHook(0x430690, CPickups::ModelForWeapon, PATCH_JUMP);
-	InjectHook(0x4306F0, CPickups::WeaponForModel, PATCH_JUMP);
-	InjectHook(0x431510, CPickups::FindColourIndexForWeaponMI, PATCH_JUMP);/**/
-	InjectHook(0x433DF0, CPickups::GetActualPickupIndex, PATCH_JUMP);
-	InjectHook(0x433DB0, CPickups::GetNewUniquePickupIndex, PATCH_JUMP);
-	InjectHook(0x433B60, CPickups::PassTime, PATCH_JUMP);
-	InjectHook(0x4339F0, CPickups::GivePlayerGoodiesWithPickUpMI, PATCH_JUMP);
-	InjectHook(0x433F60, CPickups::Load, PATCH_JUMP);
-	InjectHook(0x433E40, CPickups::Save, PATCH_JUMP);
-	InjectHook(0x433BA0, &CPickup::GiveUsAPickUpObject, PATCH_JUMP);
-	InjectHook(0x430860, &CPickup::Update, PATCH_JUMP);
-ENDPATCHES
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+
+#include "Camera.h"
+#include "Coronas.h"
+#include "Darkel.h"
+#include "Entity.h"
+#include "Explosion.h"
+#include "Font.h"
+#include "Garages.h"
+#include "General.h"
+#include "ModelIndices.h"
+#include "Object.h"
+#include "Pad.h"
+#include "Pickups.h"
+#include "PlayerPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
+#include "Fire.h"
+#include "PointLights.h"
+#include "Pools.h"
+#ifdef FIX_BUGS
+#include "Replay.h"
+#endif
+#include "Script.h"
+#include "Shadows.h"
+#include "SpecialFX.h"
+#include "Sprite.h"
+#include "Timer.h"
+#include "WaterLevel.h"
+#include "World.h"
+
+CPickup(&CPickups::aPickUps)[NUMPICKUPS] = *(CPickup(*)[NUMPICKUPS])*(uintptr*)0x878C98;
+int16 CPickups::NumMessages;// = *(int16*)0x95CC98;
+int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS];// = *(int32(*)[NUMCOLLECTEDPICKUPS])*(uintptr*)0x87C538;
+int16 CPickups::CollectedPickUpIndex;// = *(int16*)0x95CC8A;
+
+// unused
+bool &CPickups::bPickUpcamActivated = *(bool*)0x95CD71;
+CVehicle *&CPickups::pPlayerVehicle = *(CVehicle**)0x8F29E8;
+CVector &CPickups::StaticCamCoors = *(CVector*)0x9404C8;
+uint32 &CPickups::StaticCamStartTime = *(uint32*)0x8E289C;
+
+tPickupMessage CPickups::aMessages[NUMPICKUPMESSAGES];
+
+// 20 ?! Some Miami leftover? (Originally at 0x5ED8D4)
+uint16 AmmoForWeapon[20] = { 0, 1, 45, 125, 25, 150, 300, 25, 5, 250, 5, 5, 0, 500, 0, 100, 0, 0, 0, 0 };
+uint16 AmmoForWeapon_OnStreet[20] = { 0, 1, 9, 25, 5, 30, 60, 5, 1, 50, 1, 1, 0, 200, 0, 100, 0, 0, 0, 0 };
+uint16 CostOfWeapon[20] = { 0, 10, 250, 800, 1500, 3000, 5000, 10000, 25000, 25000, 2000, 2000, 0, 50000, 0, 3000, 0, 0, 0, 0 };
+
+uint8 aWeaponReds[] = { 255, 0, 128, 255, 255, 0, 255, 0, 128, 128, 255, 255, 128, 0, 255, 0 };
+uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 255, 0, 255, 0 };
+uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 };
+float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f };
+
+void
+CPickup::RemoveKeepType()
+{
+	CWorld::Remove(m_pObject);
+	delete m_pObject;
+
+	m_bRemoved = true;
+	m_pObject = nil;
+}
+
+void
+CPickup::Remove()
+{
+	RemoveKeepType();
+	m_eType = PICKUP_NONE;
+}
+
+CObject *
+CPickup::GiveUsAPickUpObject(int32 handle)
+{
+	CObject *object;
+
+	if (handle <= 0) object = new CObject(m_eModelIndex, false);
+	else {
+		CPools::MakeSureSlotInObjectPoolIsEmpty(handle);
+		object = new(handle) CObject(m_eModelIndex, false);
+	}
+
+	if (object == nil) return nil;
+	object->ObjectCreatedBy = MISSION_OBJECT;
+	object->GetPosition() = m_vecPos;
+	object->SetOrientation(0.0f, 0.0f, -HALFPI);
+	object->GetMatrix().UpdateRW();
+	object->UpdateRwFrame();
+
+	object->bAffectedByGravity = false;
+	object->bExplosionProof = true;
+	object->bUsesCollision = false;
+	object->bIsPickup = true;
+
+	object->m_nBonusValue = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0;
+
+	switch (m_eType)
+	{
+	case PICKUP_IN_SHOP:
+		object->m_obj_flag2 = true;
+		object->bOutOfStock = false;
+		break;
+	case PICKUP_ON_STREET:
+	case PICKUP_ONCE:
+	case PICKUP_ONCE_TIMEOUT:
+	case PICKUP_COLLECTABLE1:
+	case PICKUP_MONEY:
+	case PICKUP_MINE_INACTIVE:
+	case PICKUP_MINE_ARMED:
+	case PICKUP_NAUTICAL_MINE_INACTIVE:
+	case PICKUP_NAUTICAL_MINE_ARMED:
+	case PICKUP_FLOATINGPACKAGE:
+	case PICKUP_ON_STREET_SLOW:
+		object->m_obj_flag2 = false;
+		object->bOutOfStock = false;
+		break;
+	case PICKUP_IN_SHOP_OUT_OF_STOCK:
+		object->m_obj_flag2 = false;
+		object->bOutOfStock = true;
+		object->bRenderScorched = true;
+		break;
+	case PICKUP_FLOATINGPACKAGE_FLOATING:
+	default:
+		break;
+	}
+	return object;
+}
+
+bool
+CPickup::CanBePickedUp(CPlayerPed *player)
+{
+	assert(m_pObject != nil);
+	bool cannotBePickedUp =
+		(m_pObject->GetModelIndex() == MI_PICKUP_BODYARMOUR && player->m_fArmour > 99.5f)
+		|| (m_pObject->GetModelIndex() == MI_PICKUP_HEALTH && player->m_fHealth > 99.5f)
+		|| (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE && player->m_pWanted->m_nWantedLevel == 0)
+		|| (m_pObject->GetModelIndex() == MI_PICKUP_KILLFRENZY && (CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame));
+	return !cannotBePickedUp;
+}
+
+bool
+CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId)
+{
+	float waterLevel;
+
+	if (m_bRemoved) {
+		if (CTimer::GetTimeInMilliseconds() > m_nTimer) {
+			// respawn pickup if we're far enough
+			float dist = (FindPlayerCoors().x - m_vecPos.x) * (FindPlayerCoors().x - m_vecPos.x) + (FindPlayerCoors().y - m_vecPos.y) * (FindPlayerCoors().y - m_vecPos.y);
+			if (dist > 100.0f || m_eType == PICKUP_IN_SHOP && dist > 2.4f) {
+				m_pObject = GiveUsAPickUpObject(-1);
+				if (m_pObject) {
+					CWorld::Add(m_pObject);
+					m_bRemoved = false;
+				}
+			}
+		}
+		return false;
+	}
+
+	if (!m_pObject) return false;
+
+	if (!IsMine()) {
+		// let's check if we touched the pickup
+		bool isPickupTouched = false;
+		if (m_pObject->GetModelIndex() == MI_PICKUP_BRIBE) {
+			if (vehicle != nil) {
+				if (vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f))
+					isPickupTouched = true;
+			}
+			else {
+				if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
+					if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
+						(player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
+						isPickupTouched = true;
+				}
+			}
+		} else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA) {
+			if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
+				isPickupTouched = true;
+			}
+		} else if (vehicle == nil) {
+			if (Abs(player->GetPosition().z - m_pObject->GetPosition().z) < 2.0f) {
+				if ((player->GetPosition().x - m_pObject->GetPosition().x) * (player->GetPosition().x - m_pObject->GetPosition().x) +
+					(player->GetPosition().y - m_pObject->GetPosition().y) * (player->GetPosition().y - m_pObject->GetPosition().y) < 1.8f)
+					isPickupTouched = true;
+			}
+		}
+
+		// if we didn't then we've got nothing to do
+		if (isPickupTouched && CanBePickedUp(player)) {
+			CPad::GetPad(0)->StartShake(120, 100);
+			switch (m_eType)
+			{
+			case PICKUP_IN_SHOP:
+				if (CWorld::Players[playerId].m_nMoney < CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]) {
+					CGarages::TriggerMessage("PU_MONY", -1, 6000, -1);
+				} else {
+					CWorld::Players[playerId].m_nMoney -= CostOfWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())];
+					if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
+						player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
+						player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
+						DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON_BOUGHT, m_pObject->GetModelIndex() - MI_GRENADE);
+					}
+					RemoveKeepType();
+					m_nTimer = CTimer::GetTimeInMilliseconds() + 5000;
+					return true;
+				}
+				break;
+			case PICKUP_ON_STREET:
+			case PICKUP_ON_STREET_SLOW:
+				if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
+					if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
+						player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon_OnStreet[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
+						if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED)) {
+							player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
+						}
+						DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
+					} else if (m_pObject->GetModelIndex() == MI_PICKUP_CAMERA && vehicle != nil) {
+						DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+						CPickups::bPickUpcamActivated = true;
+						CPickups::pPlayerVehicle = FindPlayerVehicle();
+						CPickups::StaticCamCoors = m_pObject->GetPosition();
+						CPickups::StaticCamStartTime = CTimer::GetTimeInMilliseconds();
+					}
+				}
+				if (m_eType == PICKUP_ON_STREET) {
+					m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
+				} else if (m_eType == PICKUP_ON_STREET_SLOW) {
+					if (MI_PICKUP_BRIBE == m_pObject->m_modelIndex)
+						m_nTimer = CTimer::GetTimeInMilliseconds() + 300000;
+					else
+						m_nTimer = CTimer::GetTimeInMilliseconds() + 720000;
+				}
+
+				RemoveKeepType();
+				return true;
+			case PICKUP_ONCE:
+			case PICKUP_ONCE_TIMEOUT:
+				if (!CPickups::GivePlayerGoodiesWithPickUpMI(m_pObject->GetModelIndex(), playerId)) {
+					if (CPickups::WeaponForModel(m_pObject->GetModelIndex())) {
+						player->GiveWeapon(CPickups::WeaponForModel(m_pObject->GetModelIndex()), m_nQuantity != 0 ? m_nQuantity : AmmoForWeapon[CPickups::WeaponForModel(m_pObject->GetModelIndex())]);
+						if (player->m_nSelectedWepSlot == player->GetWeaponSlot(WEAPONTYPE_UNARMED))
+							player->m_nSelectedWepSlot = player->GetWeaponSlot(CPickups::WeaponForModel(m_pObject->GetModelIndex()));
+					}
+					DMAudio.PlayFrontEndSound(SOUND_PICKUP_WEAPON, m_pObject->GetModelIndex() - MI_GRENADE);
+				}
+				Remove();
+				return true;
+			case PICKUP_COLLECTABLE1:
+				CWorld::Players[playerId].m_nCollectedPackages++;
+				CWorld::Players[playerId].m_nMoney += 1000;
+
+				if (CWorld::Players[playerId].m_nCollectedPackages == CWorld::Players[playerId].m_nTotalPackages) {
+					printf("All collectables have been picked up\n");
+					CGarages::TriggerMessage("CO_ALL", -1, 5000, -1);
+					CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1000000;
+				} else
+					CGarages::TriggerMessage("CO_ONE", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 5000, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
+
+				Remove();
+				DMAudio.PlayFrontEndSound(SOUND_PICKUP_HIDDEN_PACKAGE, 0);
+				return true;
+			case PICKUP_MONEY:
+				CWorld::Players[playerId].m_nMoney += m_nQuantity;
+				sprintf(gString, "$%d", m_nQuantity);
+#ifdef MONEY_MESSAGES
+				CMoneyMessages::RegisterOne(m_vecPos + CVector(0.0f, 0.0f, 1.0f), gString, 0, 255, 0, 0.5f, 0.5f);
+#endif
+				Remove();
+				DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0);
+				return true;
+			default:
+				break;
+			}
+		}
+	} else {
+		switch (m_eType)
+		{
+		case PICKUP_MINE_INACTIVE:
+			if (vehicle != nil && !vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
+				m_eType = PICKUP_MINE_ARMED;
+				m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
+			}
+			break;
+		case PICKUP_NAUTICAL_MINE_INACTIVE:
+		{
+			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
+				m_pObject->GetPosition().z = waterLevel + 0.6f;
+
+			m_pObject->GetMatrix().UpdateRW();
+			m_pObject->UpdateRwFrame();
+
+			bool touched = false;
+			for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
+				CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
+				if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
+					touched = true;
+					break; // added break here
+				}
+			}
+
+			if (!touched) {
+				m_eType = PICKUP_NAUTICAL_MINE_ARMED;
+				m_nTimer = CTimer::GetTimeInMilliseconds() + 10000;
+			}
+			break;
+		}
+		case PICKUP_NAUTICAL_MINE_ARMED:
+			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false))
+				m_pObject->GetPosition().z = waterLevel + 0.6f;
+
+			m_pObject->GetMatrix().UpdateRW();
+			m_pObject->UpdateRwFrame();
+			// no break here
+		case PICKUP_MINE_ARMED:
+		{
+			bool explode = false;
+			if (CTimer::GetTimeInMilliseconds() > m_nTimer)
+				explode = true;
+			else {// added else here since vehicle lookup is useless
+				for (int32 i = CPools::GetVehiclePool()->GetSize()-1; i >= 0; i--) {
+					CVehicle *vehicle = CPools::GetVehiclePool()->GetSlot(i);
+					if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 1.5f)) {
+						explode = true;
+						break; // added break here
+					}
+				}
+			}
+			if (explode) {
+				CExplosion::AddExplosion(nil, nil, EXPLOSION_MINE, m_pObject->GetPosition(), 0);
+				Remove();
+			}
+			break;
+		}
+		case PICKUP_FLOATINGPACKAGE:
+			m_pObject->m_vecMoveSpeed.z -= 0.01f * CTimer::GetTimeStep();
+			m_pObject->GetPosition() += m_pObject->GetMoveSpeed() * CTimer::GetTimeStep();
+
+			m_pObject->GetMatrix().UpdateRW();
+			m_pObject->UpdateRwFrame();
+			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z)
+				m_eType = PICKUP_FLOATINGPACKAGE_FLOATING;
+			break;
+		case PICKUP_FLOATINGPACKAGE_FLOATING:
+			if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0))
+				m_pObject->GetPosition().z = waterLevel;
+
+			m_pObject->GetMatrix().UpdateRW();
+			m_pObject->UpdateRwFrame();
+			if (vehicle != nil && vehicle->IsSphereTouchingVehicle(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z, 2.0f)) {
+				Remove();
+				DMAudio.PlayFrontEndSound(SOUND_PICKUP_FLOAT_PACKAGE, 0);
+				return true;
+			}
+			break;
+		}
+	}
+	if (!m_bRemoved && (m_eType == PICKUP_ONCE_TIMEOUT || m_eType == PICKUP_MONEY) && CTimer::GetTimeInMilliseconds() > m_nTimer)
+		Remove();
+	return false;
+}
+
+void
+CPickups::Init(void)
+{
+	NumMessages = 0;
+	for (int i = 0; i < NUMPICKUPS; i++) {
+		aPickUps[i].m_eType = PICKUP_NONE;
+		aPickUps[i].m_nIndex = 1;
+		aPickUps[i].m_pObject = nil;
+	}
+
+	for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++)
+		aPickUpsCollected[i] = 0;
+
+	CollectedPickUpIndex = 0;
+}
+
+bool
+CPickups::IsPickUpPickedUp(int32 pickupId)
+{
+	for (int i = 0; i < NUMCOLLECTEDPICKUPS; i++) {
+		if (pickupId == aPickUpsCollected[i]) {
+			aPickUpsCollected[i] = 0;
+			return true;
+		}
+	}
+	return false;
+}
+
+void
+CPickups::PassTime(uint32 time)
+{
+	for (int i = 0; i < NUMPICKUPS; i++) {
+		if (aPickUps[i].m_eType != PICKUP_NONE) {
+			if (aPickUps[i].m_nTimer <= time)
+				aPickUps[i].m_nTimer = 0;
+			else
+				aPickUps[i].m_nTimer -= time;
+		}
+	}
+}
+
+int32
+CPickups::GetActualPickupIndex(int32 index)
+{
+	if (index == -1) return -1;
+
+	// doesn't look nice
+	if ((uint16)((index & 0xFFFF0000) >> 16) != aPickUps[(uint16)index].m_nIndex) return -1;
+	return (uint16)index;
+}
+
+bool
+CPickups::GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex)
+{
+	CPlayerPed *player;
+
+	if (playerIndex <= 0) player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+	else player = CWorld::Players[playerIndex].m_pPed;
+
+	if (modelIndex == MI_PICKUP_ADRENALINE) {
+		player->m_bAdrenalineActive = true;
+		player->m_nAdrenalineTime = CTimer::GetTimeInMilliseconds() + 20000;
+		player->m_fCurrentStamina = player->m_fMaxStamina;
+		DMAudio.PlayFrontEndSound(SOUND_PICKUP_ADRENALINE, 0);
+		return true;
+	} else if (modelIndex == MI_PICKUP_BODYARMOUR) {
+		player->m_fArmour = 100.0f;
+		DMAudio.PlayFrontEndSound(SOUND_PICKUP_ARMOUR, 0);
+		return true;
+	} else if (modelIndex == MI_PICKUP_INFO) {
+		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+		return true;
+	} else if (modelIndex == MI_PICKUP_HEALTH) {
+		player->m_fHealth = 100.0f;
+		DMAudio.PlayFrontEndSound(SOUND_PICKUP_HEALTH, 0);
+		return true;
+	} else if (modelIndex == MI_PICKUP_BONUS) {
+		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+		return true;
+	} else if (modelIndex == MI_PICKUP_BRIBE) {
+		int32 level = FindPlayerPed()->m_pWanted->m_nWantedLevel - 1;
+		if (level < 0) level = 0;
+		player->SetWantedLevel(level);
+		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+		return true;
+	} else if (modelIndex == MI_PICKUP_KILLFRENZY) {
+		DMAudio.PlayFrontEndSound(SOUND_PICKUP_BONUS, 0);
+		return true;
+	}
+	return false;
+}
+
+void
+CPickups::RemoveAllFloatingPickups()
+{
+	for (int i = 0; i < NUMPICKUPS; i++) {
+		if (aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE || aPickUps[i].m_eType == PICKUP_FLOATINGPACKAGE_FLOATING) {
+			if (aPickUps[i].m_pObject) {
+				CWorld::Remove(aPickUps[i].m_pObject);
+				delete aPickUps[i].m_pObject;
+				aPickUps[i].m_pObject = nil;
+			}
+		}
+	}
+}
+
+void
+CPickups::RemovePickUp(int32 pickupIndex)
+{
+	int32 index = CPickups::GetActualPickupIndex(pickupIndex);
+	if (index == -1) return;
+
+	if (aPickUps[index].m_pObject) {
+		CWorld::Remove(aPickUps[index].m_pObject);
+		delete aPickUps[index].m_pObject;
+		aPickUps[index].m_pObject = nil;
+	}
+	aPickUps[index].m_eType = PICKUP_NONE;
+	aPickUps[index].m_bRemoved = true;
+}
+
+int32
+CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity)
+{
+	bool bFreeFound = false;
+	int32 slot = 0;
+
+	if (type == PICKUP_FLOATINGPACKAGE || type == PICKUP_NAUTICAL_MINE_INACTIVE) {
+		for (slot = NUMPICKUPS; slot >= 0; slot--) {
+			if (aPickUps[slot].m_eType == PICKUP_NONE) {
+				bFreeFound = true;
+				break;
+			}
+		}
+	} else {
+		for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
+			if (aPickUps[slot].m_eType == PICKUP_NONE) {
+				bFreeFound = true;
+				break;
+			}
+		}
+	}
+
+	if (!bFreeFound) {
+		for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
+			if (aPickUps[slot].m_eType == PICKUP_MONEY) break;
+		}
+
+		if (slot >= NUMGENERALPICKUPS) {
+			for (slot = 0; slot < NUMGENERALPICKUPS; slot++) {
+				if (aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT) break;
+			}
+
+			if (slot >= NUMGENERALPICKUPS) return -1;
+		}
+	}
+
+	if (slot >= NUMPICKUPS) return -1;
+
+	aPickUps[slot].m_eType = (ePickupType)type;
+	aPickUps[slot].m_bRemoved = false;
+	aPickUps[slot].m_nQuantity = quantity;
+	if (type == PICKUP_ONCE_TIMEOUT)
+		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 20000;
+	else if (type == PICKUP_MONEY)
+		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 30000;
+	else if (type == PICKUP_MINE_INACTIVE || type == PICKUP_MINE_ARMED) {
+		aPickUps[slot].m_eType = PICKUP_MINE_INACTIVE;
+		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
+	} else if (type == PICKUP_NAUTICAL_MINE_INACTIVE || type == PICKUP_NAUTICAL_MINE_ARMED) {
+		aPickUps[slot].m_eType = PICKUP_NAUTICAL_MINE_INACTIVE;
+		aPickUps[slot].m_nTimer = CTimer::GetTimeInMilliseconds() + 1500;
+	}
+	aPickUps[slot].m_eModelIndex = modelIndex;
+	aPickUps[slot].m_vecPos = pos;
+	aPickUps[slot].m_pObject = aPickUps[slot].GiveUsAPickUpObject(-1);
+	if (aPickUps[slot].m_pObject)
+		CWorld::Add(aPickUps[slot].m_pObject);
+	return GetNewUniquePickupIndex(slot);
+}
+
+int32
+CPickups::GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity)
+{
+	return GenerateNewOne(pos, ModelForWeapon(weaponType), type, quantity);
+}
+
+int32
+CPickups::GetNewUniquePickupIndex(int32 slot)
+{
+	if (aPickUps[slot].m_nIndex >= 0xFFFE)
+		aPickUps[slot].m_nIndex = 1;
+	else
+		aPickUps[slot].m_nIndex++;
+	return slot | (aPickUps[slot].m_nIndex << 16);
+}
+
+int32
+CPickups::ModelForWeapon(eWeaponType weaponType)
+{
+	switch (weaponType)
+	{
+	case WEAPONTYPE_BASEBALLBAT: return MI_BASEBALL_BAT;
+	case WEAPONTYPE_COLT45: return MI_COLT;
+	case WEAPONTYPE_UZI: return MI_UZI;
+	case WEAPONTYPE_SHOTGUN: return MI_SHOTGUN;
+	case WEAPONTYPE_AK47: return MI_AK47;
+	case WEAPONTYPE_M16: return MI_M16;
+	case WEAPONTYPE_SNIPERRIFLE: return MI_SNIPER;
+	case WEAPONTYPE_ROCKETLAUNCHER: return MI_ROCKETLAUNCHER;
+	case WEAPONTYPE_FLAMETHROWER: return MI_FLAMETHROWER;
+	case WEAPONTYPE_MOLOTOV: return MI_MOLOTOV;
+	case WEAPONTYPE_GRENADE: return MI_GRENADE;
+	}
+	return 0;
+}
+
+eWeaponType
+CPickups::WeaponForModel(int32 model)
+{
+	if (model == MI_PICKUP_BODYARMOUR) return WEAPONTYPE_ARMOUR;
+	switch (model)
+	{
+	case MI_GRENADE: return WEAPONTYPE_GRENADE;
+	case MI_AK47: return WEAPONTYPE_AK47;
+	case MI_BASEBALL_BAT: return WEAPONTYPE_BASEBALLBAT;
+	case MI_COLT: return WEAPONTYPE_COLT45;
+	case MI_MOLOTOV: return WEAPONTYPE_MOLOTOV;
+	case MI_ROCKETLAUNCHER: return WEAPONTYPE_ROCKETLAUNCHER;
+	case MI_SHOTGUN: return WEAPONTYPE_SHOTGUN;
+	case MI_SNIPER: return WEAPONTYPE_SNIPERRIFLE;
+	case MI_UZI: return WEAPONTYPE_UZI;
+	case MI_MISSILE: return WEAPONTYPE_UNARMED;
+	case MI_M16: return WEAPONTYPE_M16;
+	case MI_FLAMETHROWER: return WEAPONTYPE_FLAMETHROWER;
+	}
+	return WEAPONTYPE_UNARMED;
+}
+
+int32
+CPickups::FindColourIndexForWeaponMI(int32 model)
+{
+	return WeaponForModel(model) - 1;
+}
+
+void
+CPickups::AddToCollectedPickupsArray(int32 index)
+{
+	aPickUpsCollected[CollectedPickUpIndex++] = index | (aPickUps[index].m_nIndex << 16);
+	if (CollectedPickUpIndex >= NUMCOLLECTEDPICKUPS)
+		CollectedPickUpIndex = 0;
+}
+
+void
+CPickups::Update()
+{
+#ifdef FIX_BUGS // RIP speedrunning (solution from SA)
+	if (CReplay::IsPlayingBack())
+		return;
+#endif
+#define PICKUPS_FRAME_SPAN (6)
+#ifdef FIX_BUGS
+	for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) {
+#else // BUG: this code can only reach 318 out of 320 pickups
+	for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) {
+#endif
+		if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
+			AddToCollectedPickupsArray(i);
+		}
+	}
+#undef PICKUPS_FRAME_SPAN
+	for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) {
+		if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) {
+			AddToCollectedPickupsArray(i);
+		}
+	}
+}
+
+void
+CPickups::DoPickUpEffects(CEntity *entity)
+{
+	if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
+		entity->bDoNotRender = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame;
+
+	if (!entity->bDoNotRender) {
+		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
+		float modifiedSin = 0.3f * (s + 1.0f);
+
+
+		int16 colorId;
+
+		if (entity->GetModelIndex() == MI_PICKUP_ADRENALINE || entity->GetModelIndex() == MI_PICKUP_CAMERA)
+			colorId = 11;
+		else if (entity->GetModelIndex() == MI_PICKUP_BODYARMOUR || entity->GetModelIndex() == MI_PICKUP_BRIBE)
+			colorId = 12;
+		else if (entity->GetModelIndex() == MI_PICKUP_INFO || entity->GetModelIndex() == MI_PICKUP_KILLFRENZY)
+			colorId = 13;
+		else if (entity->GetModelIndex() == MI_PICKUP_HEALTH || entity->GetModelIndex() == MI_PICKUP_BONUS)
+			colorId = 14;
+		else
+			colorId = FindColourIndexForWeaponMI(entity->GetModelIndex());
+
+		assert(colorId >= 0);
+
+		CVector &pos = entity->GetPosition();
+
+		float colorModifier = ((CGeneral::GetRandomNumber() & 0x1F) * 0.015f + 1.0f) * modifiedSin * 0.15f;
+		CShadows::StoreStaticShadow(
+			(uintptr)entity,
+			SHADOWTYPE_ADDITIVE,
+			gpShadowExplosionTex,
+			&pos,
+			2.0f, 0.0f, 0.0f, -2.0f,
+			255,                                        // this is 0 on PC which results in no shadow
+			aWeaponReds[colorId] * colorModifier, aWeaponGreens[colorId] * colorModifier, aWeaponBlues[colorId] * colorModifier,
+			4.0f, 1.0f, 40.0f, false, 0.0f);
+
+		float radius = (CGeneral::GetRandomNumber() & 0xF) * 0.1f + 3.0f;
+		CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f), radius, aWeaponReds[colorId] * modifiedSin / 256.0f, aWeaponGreens[colorId] * modifiedSin / 256.0f, aWeaponBlues[colorId] * modifiedSin / 256.0f, CPointLights::FOG_NONE, true);
+		float size = (CGeneral::GetRandomNumber() & 0xF) * 0.0005f + 0.6f;
+		CCoronas::RegisterCorona( (uintptr)entity,
+			aWeaponReds[colorId] * modifiedSin / 2.0f, aWeaponGreens[colorId] * modifiedSin / 2.0f, aWeaponBlues[colorId] * modifiedSin / 2.0f,
+			255,
+			pos,
+			size, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+
+		CObject *object = (CObject*)entity;
+		if (object->m_obj_flag2 || object->bOutOfStock || object->m_nBonusValue) {
+			float dist = (TheCamera.GetPosition() - pos).Magnitude();
+			const float MAXDIST = 12.0f;
+
+			if (dist < MAXDIST && NumMessages < NUMPICKUPMESSAGES) {
+				RwV3d vecOut;
+				float fDistX, fDistY;
+				if (CSprite::CalcScreenCoors(entity->GetPosition() + CVector(0.0f, 0.0f, 0.7f), &vecOut, &fDistX, &fDistY, true)) {
+					aMessages[NumMessages].m_pos.x = vecOut.x;
+					aMessages[NumMessages].m_pos.y = vecOut.y;
+					aMessages[NumMessages].m_dist.x = fDistX;
+					aMessages[NumMessages].m_dist.y = fDistY;
+					aMessages[NumMessages].m_weaponType = WeaponForModel(entity->GetModelIndex());
+					aMessages[NumMessages].m_color.red = aWeaponReds[colorId];
+					aMessages[NumMessages].m_color.green = aWeaponGreens[colorId];
+					aMessages[NumMessages].m_color.blue = aWeaponBlues[colorId];
+					aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f;
+					aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock;
+					aMessages[NumMessages].m_quantity = object->m_nBonusValue;
+					NumMessages++;
+				}
+			}
+		}
+
+		entity->GetMatrix().SetRotateZOnlyScaled((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800), aWeaponScale[colorId]);
+	}
+}
+
+void
+CPickups::DoMineEffects(CEntity *entity)
+{
+	CVector &pos = entity->GetPosition();
+	float dist = (TheCamera.GetPosition() - pos).Magnitude();
+	const float MAXDIST = 20.0f;
+
+	if (dist < MAXDIST) {
+		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x1FF) * DEGTORAD(360.0f / 0x200));
+
+		int32 red = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 64.0f;
+		CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
+			2.0f, 0.0f, 0.0f, -2.0f,
+			255,                                        // this is 0 on PC which results in no shadow
+			red, 0, 0,
+			4.0f, 1.0f, 40.0f, false, 0.0f);
+		CCoronas::RegisterCorona((uintptr)entity, red, 0, 0, 255, pos, 0.6f, 60.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+	}
+
+	entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x3FF) * DEGTORAD(360.0f / 0x400));
+}
+
+void
+CPickups::DoMoneyEffects(CEntity *entity)
+{
+	CVector &pos = entity->GetPosition();
+	float dist = (TheCamera.GetPosition() - pos).Magnitude();
+	const float MAXDIST = 20.0f;
+
+	if (dist < MAXDIST) {
+		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x3FF) * DEGTORAD(360.0f / 0x400));
+
+		int32 green = (MAXDIST - dist) * (0.2f * s + 0.3f) / MAXDIST * 64.0f;
+		CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
+			2.0f, 0.0f, 0.0f, -2.0f,
+			255,                                        // this is 0 on PC which results in no shadow
+			0, green, 0,
+			4.0f, 1.0f, 40.0f, false, 0.0f);
+		CCoronas::RegisterCorona((uintptr)entity, 0, green, 0, 255, pos, 0.4f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+	}
+
+	entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0x7FF) * DEGTORAD(360.0f / 0x800));
+}
+
+void
+CPickups::DoCollectableEffects(CEntity *entity)
+{
+	CVector &pos = entity->GetPosition();
+	float dist = (TheCamera.GetPosition() - pos).Magnitude();
+	const float MAXDIST = 14.0f;
+
+	if (dist < MAXDIST) {
+		float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800));
+
+		int32 color = (MAXDIST - dist) * (0.5f * s + 0.5f) / MAXDIST * 255.0f;
+		CShadows::StoreStaticShadow((uintptr)entity, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos,
+			2.0f, 0.0f, 0.0f, -2.0f,
+			255,                                        // this is 0 on PC which results in no shadow
+			color, color, color,
+			4.0f, 1.0f, 40.0f, false, 0.0f);
+		CCoronas::RegisterCorona((uintptr)entity, color, color, color, 255, pos, 0.6f, 40.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+	}
+
+	entity->GetMatrix().SetRotateZOnly((float)(CTimer::GetTimeInMilliseconds() & 0xFFF) * DEGTORAD(360.0f / 0x1000));
+}
+
+void
+CPickups::RenderPickUpText()
+{
+	wchar *strToPrint;
+	for (int32 i = 0; i < NumMessages; i++) {
+		if (aMessages[i].m_quantity <= 39) {
+			switch (aMessages[i].m_quantity) // could use some enum maybe
+			{
+			case 0:
+				if (aMessages[i].m_weaponType == WEAPONTYPE_TOTALWEAPONS) { // unreachable code?
+					// what is this??
+					sprintf(gString, "%d/%d", CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages, 2903);
+				} else {
+					if (aMessages[i].m_bOutOfStock)
+						strToPrint = TheText.Get("STOCK");
+					else {
+						sprintf(gString, "$%d", CostOfWeapon[aMessages[i].m_weaponType]);
+						AsciiToUnicode(gString, gUString);
+						strToPrint = gUString;
+					}
+				}
+				break;
+			case 1:
+				strToPrint = TheText.Get("SECURI");
+				break;
+			case 2:
+				strToPrint = TheText.Get("MOONBM");
+				break;
+			case 3:
+				strToPrint = TheText.Get("COACH");
+				break;
+			case 4:
+				strToPrint = TheText.Get("FLATBED");
+				break;
+			case 5:
+				strToPrint = TheText.Get("LINERUN");
+				break;
+			case 6:
+				strToPrint = TheText.Get("TRASHM");
+				break;
+			case 7:
+				strToPrint = TheText.Get("PATRIOT");
+				break;
+			case 8:
+				strToPrint = TheText.Get("WHOOPEE");
+				break;
+			case 9:
+				strToPrint = TheText.Get("BLISTA");
+				break;
+			case 10:
+				strToPrint = TheText.Get("MULE");
+				break;
+			case 11:
+				strToPrint = TheText.Get("YANKEE");
+				break;
+			case 12:
+				strToPrint = TheText.Get("BOBCAT");
+				break;
+			case 13:
+				strToPrint = TheText.Get("DODO");
+				break;
+			case 14:
+				strToPrint = TheText.Get("BUS");
+				break;
+			case 15:
+				strToPrint = TheText.Get("RUMPO");
+				break;
+			case 16:
+				strToPrint = TheText.Get("PONY");
+				break;
+			case 17:
+				strToPrint = TheText.Get("SENTINL");
+				break;
+			case 18:
+				strToPrint = TheText.Get("CHEETAH");
+				break;
+			case 19:
+				strToPrint = TheText.Get("BANSHEE");
+				break;
+			case 20:
+				strToPrint = TheText.Get("IDAHO");
+				break;
+			case 21:
+				strToPrint = TheText.Get("INFERNS");
+				break;
+			case 22:
+				strToPrint = TheText.Get("TAXI");
+				break;
+			case 23:
+				strToPrint = TheText.Get("KURUMA");
+				break;
+			case 24:
+				strToPrint = TheText.Get("STRETCH");
+				break;
+			case 25:
+				strToPrint = TheText.Get("PEREN");
+				break;
+			case 26:
+				strToPrint = TheText.Get("STINGER");
+				break;
+			case 27:
+				strToPrint = TheText.Get("MANANA");
+				break;
+			case 28:
+				strToPrint = TheText.Get("LANDSTK");
+				break;
+			case 29:
+				strToPrint = TheText.Get("STALION");
+				break;
+			case 30:
+				strToPrint = TheText.Get("BFINJC");
+				break;
+			case 31:
+				strToPrint = TheText.Get("CABBIE");
+				break;
+			case 32:
+				strToPrint = TheText.Get("ESPERAN");
+				break;
+			case 33:
+				strToPrint = TheText.Get("FIRETRK");
+				break;
+			case 34:
+				strToPrint = TheText.Get("AMBULAN");
+				break;
+			case 35:
+				strToPrint = TheText.Get("ENFORCR");
+				break;
+			case 36:
+				strToPrint = TheText.Get("FBICAR");
+				break;
+			case 37:
+				strToPrint = TheText.Get("RHINO");
+				break;
+			case 38:
+				strToPrint = TheText.Get("BARRCKS");
+				break;
+			case 39:
+				strToPrint = TheText.Get("POLICAR");
+				break;
+			default:
+				break;
+			}
+		}
+		CFont::SetPropOn();
+		CFont::SetBackgroundOff();
+
+		const float MAX_SCALE = 1.0f;
+
+		float fScaleY = aMessages[i].m_dist.y / 100.0f;
+		if (fScaleY > MAX_SCALE) fScaleY = MAX_SCALE;
+
+		float fScaleX = aMessages[i].m_dist.x / 100.0f;
+		if (fScaleX > MAX_SCALE) fScaleX = MAX_SCALE;
+
+		CFont::SetScale(fScaleX, fScaleY);
+		CFont::SetCentreOn();
+		CFont::SetCentreSize(SCREEN_WIDTH);
+		CFont::SetJustifyOff();
+
+		CFont::SetColor(CRGBA(aMessages[i].m_color.red, aMessages[i].m_color.green, aMessages[i].m_color.blue, aMessages[i].m_color.alpha));
+		CFont::SetBackGroundOnlyTextOff();
+		CFont::SetFontStyle(FONT_BANK);
+		CFont::PrintString(aMessages[i].m_pos.x, aMessages[i].m_pos.y, strToPrint);
+	}
+	NumMessages = 0;
+}
+
+void
+CPickups::Load(uint8 *buf, uint32 size)
+{
+INITSAVEBUF
+
+	for (int32 i = 0; i < NUMPICKUPS; i++) {
+		aPickUps[i] = ReadSaveBuf<CPickup>(buf);
+
+		if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil)
+			aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((int32)aPickUps[i].m_pObject - 1);
+	}
+
+	CollectedPickUpIndex = ReadSaveBuf<uint16>(buf);
+	ReadSaveBuf<uint16>(buf);
+	NumMessages = 0;
+
+	for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
+		aPickUpsCollected[i] = ReadSaveBuf<int32>(buf);
+
+VALIDATESAVEBUF(size)
+}
+
+void
+CPickups::Save(uint8 *buf, uint32 *size)
+{
+	*size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected);
+
+INITSAVEBUF
+
+	for (int32 i = 0; i < NUMPICKUPS; i++) {
+		CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]);
+		if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil)
+			buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1);
+	}
+
+	WriteSaveBuf(buf, CollectedPickUpIndex);
+	WriteSaveBuf(buf, (uint16)0); // possibly was NumMessages
+
+	for (uint16 i = 0; i < NUMCOLLECTEDPICKUPS; i++)
+		WriteSaveBuf(buf, aPickUpsCollected[i]);
+
+VALIDATESAVEBUF(*size)
+}
+
+void
+CPacManPickup::Update()
+{
+	if (FindPlayerVehicle() == nil) return;
+
+	CVehicle *veh = FindPlayerVehicle();
+	
+	if (DistanceSqr2D(FindPlayerVehicle()->GetPosition(), m_vecPosn.x, m_vecPosn.y) < 100.0f && veh->IsSphereTouchingVehicle(m_vecPosn.x, m_vecPosn.y, m_vecPosn.z, 1.5f)) {
+		switch (m_eType)
+		{
+		case PACMAN_SCRAMBLE:
+		{
+			veh->m_nPacManPickupsCarried++;
+			veh->m_vecMoveSpeed *= 0.65f;
+			float massMult = (veh->m_fMass + 250.0f) / veh->m_fMass;
+			veh->m_fMass *= massMult;
+			veh->m_fTurnMass *= massMult;
+			veh->m_fForceMultiplier *= massMult;
+			FindPlayerPed()->m_pWanted->m_nChaos += 10;
+			FindPlayerPed()->m_pWanted->UpdateWantedLevel();
+			DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PACKAGE, 0);
+			break;
+		}
+		case PACMAN_RACE:
+			CPacManPickups::PillsEatenInRace++;
+			DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PILL, 0);
+			break;
+		default:
+			break;
+		}
+		m_eType = PACMAN_NONE;
+		if (m_pObject != nil) {
+			CWorld::Remove(m_pObject);
+			delete m_pObject;
+			m_pObject = nil;
+		}
+	}
+}
+
+int32 CollectGameState;
+int16 ThingsToCollect;
+
+CPacManPickup CPacManPickups::aPMPickUps[NUMPACMANPICKUPS];
+CVector CPacManPickups::LastPickUpCoors;
+int32 CPacManPickups::PillsEatenInRace;
+bool CPacManPickups::bPMActive;
+
+void
+CPacManPickups::Init()
+{
+	for (int i = 0; i < NUMPACMANPICKUPS; i++)
+		aPMPickUps[i].m_eType = PACMAN_NONE;
+	bPMActive = false;
+}
+
+void
+CPacManPickups::Update()
+{
+	if (FindPlayerVehicle()) {
+		float dist = Distance(FindPlayerCoors(), CVector(1072.0f, -948.0f, 14.5f));
+		switch (CollectGameState) {
+		case 1:
+			if (dist < 10.0f) {
+				ThingsToCollect -= FindPlayerVehicle()->m_nPacManPickupsCarried;
+				FindPlayerVehicle()->m_nPacManPickupsCarried = 0;
+				FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier;
+				FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier;
+				FindPlayerVehicle()->m_fForceMultiplier = 1.0f;
+			}
+			if (ThingsToCollect <= 0) {
+				CollectGameState = 2;
+				ClearPMPickUps();
+			}
+			break;
+		case 2:
+			if (dist > 11.0f)
+				CollectGameState = 0;
+			break;
+		case 20:
+			if (Distance(FindPlayerCoors(), LastPickUpCoors) > 30.0f) {
+				LastPickUpCoors = FindPlayerCoors();
+				printf("%f, %f, %f,\n", LastPickUpCoors.x, LastPickUpCoors.y, LastPickUpCoors.z);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	if (bPMActive) {
+#define PACMANPICKUPS_FRAME_SPAN (4)
+		for (uint32 i = (CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i < ((CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) + 1) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i++) {
+			if (aPMPickUps[i].m_eType != PACMAN_NONE)
+				aPMPickUps[i].Update();
+		}
+#undef PACMANPICKUPS_FRAME_SPAN
+	}
+}
+
+void
+CPacManPickups::GeneratePMPickUps(CVector pos, float scrambleMult, int16 count, uint8 type)
+{
+	int i = 0;
+	while (count > 0) {
+		while (aPMPickUps[i].m_eType != PACMAN_NONE)
+			i++;
+
+		bool bPickupCreated = false;
+		while (!bPickupCreated) {
+			CVector newPos = pos;
+			CColPoint colPoint;
+			CEntity *pRoad;
+			uint16 nRand = CGeneral::GetRandomNumber();
+			newPos.x += ((nRand & 0xFF) - 128) * scrambleMult / 128.0f;
+			newPos.y += (((nRand >> 8) & 0xFF) - 128) * scrambleMult / 128.0f;
+			newPos.z = 1000.0f;
+			if (CWorld::ProcessVerticalLine(newPos, -1000.0f, colPoint, pRoad, true, false, false, false, true, false, nil) && pRoad->IsBuilding() && ((CBuilding*)pRoad)->GetIsATreadable()) {
+				newPos.z = 0.7f + colPoint.point.z;
+				aPMPickUps[i].m_eType = type;
+				aPMPickUps[i].m_vecPosn = newPos;
+				CObject *obj = new CObject(MI_BULLION, true);
+				if (obj != nil) {
+					obj->ObjectCreatedBy = MISSION_OBJECT;
+					obj->GetPosition() = aPMPickUps[i].m_vecPosn;
+					obj->SetOrientation(0.0f, 0.0f, -HALFPI);
+					obj->GetMatrix().UpdateRW();
+					obj->UpdateRwFrame();
+
+					obj->bAffectedByGravity = false;
+					obj->bExplosionProof = true;
+					obj->bUsesCollision = false;
+					obj->bIsPickup = false;
+					CWorld::Add(obj);
+				}
+				aPMPickUps[i].m_pObject = obj;
+				bPickupCreated = true;
+			}
+		}
+		count--;
+	}
+	bPMActive = true;
+}
+
+// diablo porn mission pickups
+static const CVector aRacePoints1[] = {
+	CVector(913.62219f, -155.13692f, 4.9699469f),
+	CVector(913.92401f, -124.12943f, 4.9692569f),
+	CVector(913.27899f, -93.524231f, 7.4325991f),
+	CVector(912.60852f, -63.15905f, 7.4533591f),
+	CVector(934.22144f, -42.049122f, 7.4511471f),
+	CVector(958.88092f, -23.863735f, 7.4652338f),
+	CVector(978.50812f, -0.78458798f, 5.13515f),
+	CVector(1009.4175f, -2.1041219f, 2.4461579f),
+	CVector(1040.6313f, -2.0793829f, 2.293175f),
+	CVector(1070.7863f, -2.084095f, 2.2789791f),
+	CVector(1100.5773f, -8.468729f, 5.3248072f),
+	CVector(1119.9341f, -31.738031f, 7.1913071f),
+	CVector(1122.1664f, -62.762737f, 7.4703908f),
+	CVector(1122.814f, -93.650566f, 8.5577497f),
+	CVector(1125.8253f, -124.26616f, 9.9803305f),
+	CVector(1153.8727f, -135.47169f, 14.150617f),
+	CVector(1184.0831f, -135.82845f, 14.973998f),
+	CVector(1192.0432f, -164.57816f, 19.18627f),
+	CVector(1192.7761f, -194.28871f, 24.799675f),
+	CVector(1215.1527f, -215.0714f, 25.74975f),
+	CVector(1245.79f, -215.39304f, 28.70726f),
+	CVector(1276.2477f, -216.39485f, 33.71236f),
+	CVector(1306.5535f, -216.71007f, 39.711472f),
+	CVector(1335.0244f, -224.59329f, 46.474979f),
+	CVector(1355.4879f, -246.27664f, 49.934841f),
+	CVector(1362.6003f, -276.47064f, 49.96265f),
+	CVector(1363.027f, -307.30847f, 49.969173f),
+	CVector(1365.343f, -338.08609f, 49.967789f),
+	CVector(1367.5957f, -368.01105f, 50.092304f),
+	CVector(1368.2749f, -398.38049f, 50.061268f),
+	CVector(1366.9034f, -429.98483f, 50.057545f),
+	CVector(1356.8534f, -459.09259f, 50.035545f),
+	CVector(1335.5819f, -481.13544f, 47.217903f),
+	CVector(1306.7552f, -491.07443f, 40.202629f),
+	CVector(1275.5978f, -491.33194f, 33.969223f),
+	CVector(1244.702f, -491.46451f, 29.111021f),
+	CVector(1213.2222f, -491.8754f, 25.771168f),
+	CVector(1182.7729f, -492.19995f, 24.749964f),
+	CVector(1152.6874f, -491.42221f, 21.70038f),
+	CVector(1121.5352f, -491.94604f, 20.075182f),
+	CVector(1090.7056f, -492.63751f, 17.585758f),
+	CVector(1059.6008f, -491.65762f, 14.848632f),
+	CVector(1029.113f, -489.66031f, 14.918498f),
+	CVector(998.20679f, -486.78107f, 14.945688f),
+	CVector(968.00555f, -484.91266f, 15.001229f),
+	CVector(937.74939f, -492.09015f, 14.958629f),
+	CVector(927.17352f, -520.97736f, 14.972308f),
+	CVector(929.29749f, -552.08643f, 14.978855f),
+	CVector(950.69525f, -574.47778f, 14.972788f),
+	CVector(974.02826f, -593.56024f, 14.966445f),
+	CVector(989.04779f, -620.12854f, 14.951016f),
+	CVector(1014.1639f, -637.3905f, 14.966736f),
+	CVector(1017.5961f, -667.3736f, 14.956415f),
+	CVector(1041.9735f, -685.94391f, 15.003841f),
+	CVector(1043.3064f, -716.11298f, 14.974236f),
+	CVector(1043.5337f, -746.63855f, 14.96919f),
+	CVector(1044.142f, -776.93823f, 14.965424f),
+	CVector(1044.2657f, -807.29395f, 14.97171f),
+	CVector(1017.0797f, -820.1076f, 14.975431f),
+	CVector(986.23865f, -820.37103f, 14.972883f),
+	CVector(956.10065f, -820.23291f, 14.981133f),
+	CVector(925.86914f, -820.19049f, 14.976553f),
+	CVector(897.69702f, -831.08734f, 14.962709f),
+	CVector(868.06586f, -835.99237f, 14.970685f),
+	CVector(836.93054f, -836.84387f, 14.965049f),
+	CVector(811.63586f, -853.7915f, 15.067576f),
+	CVector(811.46344f, -884.27368f, 12.247812f),
+	CVector(811.60651f, -914.70959f, 9.2393751f),
+	CVector(811.10425f, -945.16272f, 5.817255f),
+	CVector(816.54584f, -975.64587f, 4.998558f),
+	CVector(828.2951f, -1003.3685f, 5.0471172f),
+	CVector(852.28839f, -1021.5963f, 4.9371028f),
+	CVector(882.50067f, -1025.4459f, 5.14077f),
+	CVector(912.84821f, -1026.7874f, 8.3415451f),
+	CVector(943.68274f, -1026.6914f, 11.341879f),
+	CVector(974.4129f, -1027.3682f, 14.410345f),
+	CVector(1004.1079f, -1036.0778f, 14.92961f),
+	CVector(1030.1144f, -1051.1224f, 14.850387f),
+	CVector(1058.7585f, -1060.342f, 14.821624f),
+	CVector(1087.7797f, -1068.3263f, 14.800561f),
+	CVector(1099.8807f, -1095.656f, 11.877907f),
+	CVector(1130.0005f, -1101.994f, 11.853914f),
+	CVector(1160.3809f, -1101.6355f, 11.854824f),
+	CVector(1191.8524f, -1102.1577f, 11.853843f),
+	CVector(1223.3307f, -1102.7448f, 11.852233f),
+	CVector(1253.564f, -1098.1045f, 11.853944f),
+	CVector(1262.0203f, -1069.1785f, 14.8147f),
+	CVector(1290.9998f, -1059.1882f, 14.816016f),
+	CVector(1316.246f, -1041.0635f, 14.81109f),
+	CVector(1331.7539f, -1013.835f, 14.81207f),
+	CVector(1334.0579f, -983.55402f, 14.827253f),
+	CVector(1323.2429f, -954.23083f, 14.954678f),
+	CVector(1302.7495f, -932.21216f, 14.962917f),
+	CVector(1317.418f, -905.89325f, 14.967506f),
+	CVector(1337.9503f, -883.5025f, 14.969675f),
+	CVector(1352.6929f, -855.96954f, 14.967854f),
+	CVector(1357.2388f, -826.26971f, 14.97295f),
+	CVector(1384.8668f, -812.47693f, 12.907736f),
+	CVector(1410.8983f, -795.39056f, 12.052228f),
+	CVector(1433.901f, -775.55811f, 11.96265f),
+	CVector(1443.8615f, -746.92511f, 11.976114f),
+	CVector(1457.7015f, -720.00903f, 11.971177f),
+	CVector(1481.5685f, -701.30237f, 11.977908f),
+	CVector(1511.4004f, -696.83295f, 11.972709f),
+	CVector(1542.1796f, -695.61676f, 11.970441f),
+	CVector(1570.3301f, -684.6239f, 11.969202f),
+	CVector(0.0f, 0.0f, 0.0f),
+};
+
+void
+CPacManPickups::GeneratePMPickUpsForRace(int32 race)
+{
+	const CVector *pPos = nil;
+	int i = 0;
+
+	if (race == 0) pPos = aRacePoints1; // there's only one available
+	assert(pPos != nil);
+
+	while (!pPos->IsZero()) {
+		while (aPMPickUps[i].m_eType != PACMAN_NONE)
+			i++;
+
+		aPMPickUps[i].m_eType = PACMAN_RACE;
+		aPMPickUps[i].m_vecPosn = *(pPos++);
+		if (race == 0) {
+			CObject* obj = new CObject(MI_DONKEYMAG, true);
+			if (obj != nil) {
+				obj->ObjectCreatedBy = MISSION_OBJECT;
+
+				obj->GetPosition() = aPMPickUps[i].m_vecPosn;
+				obj->SetOrientation(0.0f, 0.0f, -HALFPI);
+				obj->GetMatrix().UpdateRW();
+				obj->UpdateRwFrame();
+
+				obj->bAffectedByGravity = false;
+				obj->bExplosionProof = true;
+				obj->bUsesCollision = false;
+				obj->bIsPickup = false;
+
+				CWorld::Add(obj);
+			}
+			aPMPickUps[i].m_pObject = obj;
+		} else
+			aPMPickUps[i].m_pObject = nil;
+	}
+	bPMActive = true;
+}
+
+void
+CPacManPickups::GenerateOnePMPickUp(CVector pos)
+{
+	bPMActive = true;
+	aPMPickUps[0].m_eType = PACMAN_RACE;
+	aPMPickUps[0].m_vecPosn = pos;
+}
+
+void
+CPacManPickups::Render()
+{
+	if (!bPMActive) return;
+
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[6]));
+
+	RwV3d pos;
+	float w, h;
+
+	for (int i = 0; i < NUMPACMANPICKUPS; i++) {
+		switch (aPMPickUps[i].m_eType)
+		{
+		case PACMAN_SCRAMBLE:
+		case PACMAN_RACE:
+			if (CSprite::CalcScreenCoors(aPMPickUps[i].m_vecPosn, &pos, &w, &h, true) && pos.z < 100.0f) {
+				if (aPMPickUps[i].m_pObject != nil) {
+					aPMPickUps[i].m_pObject->GetMatrix().SetRotateZOnly((CTimer::GetTimeInMilliseconds() % 1024) * TWOPI / 1024.0f);
+					aPMPickUps[i].m_pObject->GetMatrix().UpdateRW();
+					aPMPickUps[i].m_pObject->UpdateRwFrame();
+				}
+				float fsin = Sin((CTimer::GetTimeInMilliseconds() % 1024) * 6.28f / 1024.0f); // yes, it is 6.28f when it was TWOPI just now...
+				CSprite::RenderOneXLUSprite(pos.x, pos.y, pos.z, 0.8f * w * fsin, 0.8f * h, 100, 50, 5, 255, 1.0f / pos.z, 255);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, FALSE);
+}
+
+void
+CPacManPickups::ClearPMPickUps()
+{
+	bPMActive = false;
+
+	for (int i = 0; i < NUMPACMANPICKUPS; i++) {
+		if (aPMPickUps[i].m_pObject != nil) {
+			CWorld::Remove(aPMPickUps[i].m_pObject);
+			delete aPMPickUps[i].m_pObject;
+			aPMPickUps[i].m_pObject = nil;
+		}
+		aPMPickUps[i].m_eType = PACMAN_NONE;
+	}
+}
+
+void
+CPacManPickups::StartPacManRace(int32 race)
+{
+	GeneratePMPickUpsForRace(race);
+	PillsEatenInRace = 0;
+}
+
+void
+CPacManPickups::StartPacManRecord()
+{
+	CollectGameState = 20;
+	LastPickUpCoors = FindPlayerCoors();
+}
+
+uint32
+CPacManPickups::QueryPowerPillsEatenInRace()
+{
+	return PillsEatenInRace;
+}
+
+void
+CPacManPickups::ResetPowerPillsEatenInRace()
+{
+	PillsEatenInRace = 0;
+}
+
+void
+CPacManPickups::CleanUpPacManStuff()
+{
+	ClearPMPickUps();
+}
+
+void
+CPacManPickups::StartPacManScramble(CVector pos, float scrambleMult, int16 count)
+{
+	GeneratePMPickUps(pos, scrambleMult, count, PACMAN_SCRAMBLE);
+}
+
+uint32
+CPacManPickups::QueryPowerPillsCarriedByPlayer()
+{
+	if (FindPlayerVehicle())
+		return FindPlayerVehicle()->m_nPacManPickupsCarried;
+	return 0;
+}
+
+void
+CPacManPickups::ResetPowerPillsCarriedByPlayer()
+{
+	if (FindPlayerVehicle() != nil) {
+		FindPlayerVehicle()->m_nPacManPickupsCarried = 0;
+		FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier;
+		FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier;
+		FindPlayerVehicle()->m_fForceMultiplier = 1.0f;
+	}
+}
+
+STARTPATCHES
+	InjectHook(0x430220, CPickups::Init, PATCH_JUMP);
+	InjectHook(0x4303D0, CPickups::Update, PATCH_JUMP);
+	InjectHook(0x432440, CPickups::RenderPickUpText, PATCH_JUMP);
+	InjectHook(0x431C30, CPickups::DoCollectableEffects, PATCH_JUMP);
+	InjectHook(0x431F40, CPickups::DoMoneyEffects, PATCH_JUMP);
+	InjectHook(0x4321C0, CPickups::DoMineEffects, PATCH_JUMP);
+	InjectHook(0x431520, CPickups::DoPickUpEffects, PATCH_JUMP);
+	InjectHook(0x4304B0, CPickups::GenerateNewOne, PATCH_JUMP);
+	InjectHook(0x430660, CPickups::GenerateNewOne_WeaponType, PATCH_JUMP);
+	InjectHook(0x4307A0, CPickups::RemovePickUp, PATCH_JUMP);
+	InjectHook(0x430800, CPickups::RemoveAllFloatingPickups, PATCH_JUMP);
+	InjectHook(0x433D60, CPickups::AddToCollectedPickupsArray, PATCH_JUMP);
+	InjectHook(0x430770, CPickups::IsPickUpPickedUp, PATCH_JUMP);
+	InjectHook(0x430690, CPickups::ModelForWeapon, PATCH_JUMP);
+	InjectHook(0x4306F0, CPickups::WeaponForModel, PATCH_JUMP);
+	InjectHook(0x431510, CPickups::FindColourIndexForWeaponMI, PATCH_JUMP);/**/
+	InjectHook(0x433DF0, CPickups::GetActualPickupIndex, PATCH_JUMP);
+	InjectHook(0x433DB0, CPickups::GetNewUniquePickupIndex, PATCH_JUMP);
+	InjectHook(0x433B60, CPickups::PassTime, PATCH_JUMP);
+	InjectHook(0x4339F0, CPickups::GivePlayerGoodiesWithPickUpMI, PATCH_JUMP);
+	InjectHook(0x433F60, CPickups::Load, PATCH_JUMP);
+	InjectHook(0x433E40, CPickups::Save, PATCH_JUMP);
+	InjectHook(0x433BA0, &CPickup::GiveUsAPickUpObject, PATCH_JUMP);
+	InjectHook(0x430860, &CPickup::Update, PATCH_JUMP);
+	InjectHook(0x4331B0, &CPacManPickup::Update, PATCH_JUMP);
+	InjectHook(0x432760, CPacManPickups::Init, PATCH_JUMP);
+	InjectHook(0x432800, CPacManPickups::Update, PATCH_JUMP);
+	InjectHook(0x432AE0, CPacManPickups::GeneratePMPickUps, PATCH_JUMP);
+	InjectHook(0x432D50, CPacManPickups::GeneratePMPickUpsForRace, PATCH_JUMP);
+	InjectHook(0x432F20, CPacManPickups::GenerateOnePMPickUp, PATCH_JUMP);
+	InjectHook(0x432F60, CPacManPickups::Render, PATCH_JUMP);
+	InjectHook(0x433150, CPacManPickups::ClearPMPickUps, PATCH_JUMP);
+	InjectHook(0x433340, CPacManPickups::StartPacManRace, PATCH_JUMP);
+	InjectHook(0x433360, CPacManPickups::StartPacManRecord, PATCH_JUMP);
+	InjectHook(0x4333A0, CPacManPickups::QueryPowerPillsEatenInRace, PATCH_JUMP);
+	InjectHook(0x4333B0, CPacManPickups::ResetPowerPillsEatenInRace, PATCH_JUMP);
+	InjectHook(0x4333C0, CPacManPickups::CleanUpPacManStuff, PATCH_JUMP);
+	InjectHook(0x4333D0, CPacManPickups::StartPacManScramble, PATCH_JUMP);
+	InjectHook(0x4333F0, CPacManPickups::QueryPowerPillsCarriedByPlayer, PATCH_JUMP);
+	InjectHook(0x433410, CPacManPickups::ResetPowerPillsCarriedByPlayer, PATCH_JUMP);
+
+ENDPATCHES
diff --git a/src/control/Pickups.h b/src/control/Pickups.h
index 4bb0ddff..b5b4f396 100644
--- a/src/control/Pickups.h
+++ b/src/control/Pickups.h
@@ -1,124 +1,147 @@
-#pragma once
-#include "Weapon.h"
-
-enum ePickupType : uint8
-{
-	PICKUP_NONE = 0,
-	PICKUP_IN_SHOP,
-	PICKUP_ON_STREET,
-	PICKUP_ONCE,
-	PICKUP_ONCE_TIMEOUT,
-	PICKUP_COLLECTABLE1,
-	PICKUP_IN_SHOP_OUT_OF_STOCK,
-	PICKUP_MONEY,
-	PICKUP_MINE_INACTIVE,
-	PICKUP_MINE_ARMED,
-	PICKUP_NAUTICAL_MINE_INACTIVE,
-	PICKUP_NAUTICAL_MINE_ARMED,
-	PICKUP_FLOATINGPACKAGE,
-	PICKUP_FLOATINGPACKAGE_FLOATING,
-	PICKUP_ON_STREET_SLOW,
-	PICKUP_NUMOFTYPES
-};
-
-class CEntity;
-class CObject;
-class CVehicle;
-class CPlayerPed;
-
-class CPickup
-{
-public:
-	ePickupType m_eType;
-	bool m_bRemoved;
-	uint16 m_nQuantity;
-	CObject *m_pObject;
-	uint32 m_nTimer;
-	int16 m_eModelIndex;
-	uint16 m_nIndex;
-	CVector m_vecPos;
-
-	CObject *GiveUsAPickUpObject(int32 handle);
-	bool Update(CPlayerPed *player, CVehicle *vehicle, int playerId);
-private:
-	bool IsMine() { return m_eType >= PICKUP_MINE_INACTIVE && m_eType <= PICKUP_FLOATINGPACKAGE_FLOATING; }
-	inline bool CanBePickedUp(CPlayerPed *player);
-	void RemoveKeepType();
-	void Remove();
-};
-
-static_assert(sizeof(CPickup) == 0x1C, "CPickup: error");
-
-struct tPickupMessage
-{
-	CVector2D m_pos;
-	eWeaponType m_weaponType;
-	CVector2D m_dist;
-	CRGBA m_color;
-	uint8 m_bOutOfStock : 1;
-	uint8 m_quantity;
-};
-
-class CPickups
-{
-	static int32 aPickUpsCollected[NUMCOLLECTEDPICKUPS];
-	static int16 CollectedPickUpIndex;
-	static int16 NumMessages;
-	static tPickupMessage aMessages[NUMPICKUPMESSAGES];
-public:
-	static void Init();
-	static void Update();
-	static void RenderPickUpText();
-	static void DoCollectableEffects(CEntity *ent);
-	static void DoMoneyEffects(CEntity *ent);
-	static void DoMineEffects(CEntity *ent);
-	static void DoPickUpEffects(CEntity *ent);
-	static int32 GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity);
-	static int32 GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity);
-	static void RemovePickUp(int32 pickupIndex);
-	static void RemoveAllFloatingPickups();
-	static void AddToCollectedPickupsArray(int32 index);
-	static bool IsPickUpPickedUp(int32 pickupId);
-	static int32 ModelForWeapon(eWeaponType weaponType);
-	static enum eWeaponType WeaponForModel(int32 model);
-	static int32 FindColourIndexForWeaponMI(int32 model);
-	static int32 GetActualPickupIndex(int32 index);
-	static int32 GetNewUniquePickupIndex(int32 slot);
-	static void PassTime(uint32 time);
-	static bool GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex);
-	static void Load(uint8 *buf, uint32 size);
-	static void Save(uint8 *buf, uint32 *size);
-
-	static CPickup(&aPickUps)[NUMPICKUPS];
-
-	// unused
-	static bool &bPickUpcamActivated;
-	static CVehicle *&pPlayerVehicle;
-	static CVector &StaticCamCoors;
-	static uint32 &StaticCamStartTime;
-};
-
-extern uint16 AmmoForWeapon[20];
-extern uint16 AmmoForWeapon_OnStreet[20];
-extern uint16 CostOfWeapon[20];
-
-class CPacManPickups
-{
-public:
-	static void Init(void);
-	static void Update(void);
-	static void GeneratePMPickUps(CVector, float, int16, uint8);
-	static void GeneratePMPickUpsForRace(int32);
-	static void GenerateOnePMPickUp(CVector);
-	static void Render(void);
-	static void DoCleanUpPacManStuff(void);
-	static void StartPacManRace(int32);
-	static void StartPacManRecord(void);
-	static uint32 QueryPowerPillsEatenInRace(void);
-	static void ResetPowerPillsEatenInRace(void);
-	static void CleanUpPacManStuff(void);
-	static void StartPacManScramble(CVector, float, int16);
-	static uint32 QueryPowerPillsCarriedByPlayer(void);
-	static void ResetPowerPillsCarriedByPlayer(void);
-
-};
+#pragma once
+#include "Weapon.h"
+
+enum ePickupType : uint8
+{
+	PICKUP_NONE = 0,
+	PICKUP_IN_SHOP,
+	PICKUP_ON_STREET,
+	PICKUP_ONCE,
+	PICKUP_ONCE_TIMEOUT,
+	PICKUP_COLLECTABLE1,
+	PICKUP_IN_SHOP_OUT_OF_STOCK,
+	PICKUP_MONEY,
+	PICKUP_MINE_INACTIVE,
+	PICKUP_MINE_ARMED,
+	PICKUP_NAUTICAL_MINE_INACTIVE,
+	PICKUP_NAUTICAL_MINE_ARMED,
+	PICKUP_FLOATINGPACKAGE,
+	PICKUP_FLOATINGPACKAGE_FLOATING,
+	PICKUP_ON_STREET_SLOW,
+	PICKUP_NUMOFTYPES
+};
+
+class CEntity;
+class CObject;
+class CVehicle;
+class CPlayerPed;
+
+class CPickup
+{
+public:
+	ePickupType m_eType;
+	bool m_bRemoved;
+	uint16 m_nQuantity;
+	CObject *m_pObject;
+	uint32 m_nTimer;
+	int16 m_eModelIndex;
+	uint16 m_nIndex;
+	CVector m_vecPos;
+
+	CObject *GiveUsAPickUpObject(int32 handle);
+	bool Update(CPlayerPed *player, CVehicle *vehicle, int playerId);
+private:
+	bool IsMine() { return m_eType >= PICKUP_MINE_INACTIVE && m_eType <= PICKUP_FLOATINGPACKAGE_FLOATING; }
+	inline bool CanBePickedUp(CPlayerPed *player);
+	void RemoveKeepType();
+	void Remove();
+};
+
+static_assert(sizeof(CPickup) == 0x1C, "CPickup: error");
+
+struct tPickupMessage
+{
+	CVector2D m_pos;
+	eWeaponType m_weaponType;
+	CVector2D m_dist;
+	CRGBA m_color;
+	uint8 m_bOutOfStock : 1;
+	uint8 m_quantity;
+};
+
+class CPickups
+{
+	static int32 aPickUpsCollected[NUMCOLLECTEDPICKUPS];
+	static int16 CollectedPickUpIndex;
+	static int16 NumMessages;
+	static tPickupMessage aMessages[NUMPICKUPMESSAGES];
+public:
+	static void Init();
+	static void Update();
+	static void RenderPickUpText();
+	static void DoCollectableEffects(CEntity *ent);
+	static void DoMoneyEffects(CEntity *ent);
+	static void DoMineEffects(CEntity *ent);
+	static void DoPickUpEffects(CEntity *ent);
+	static int32 GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quantity);
+	static int32 GenerateNewOne_WeaponType(CVector pos, eWeaponType weaponType, uint8 type, uint32 quantity);
+	static void RemovePickUp(int32 pickupIndex);
+	static void RemoveAllFloatingPickups();
+	static void AddToCollectedPickupsArray(int32 index);
+	static bool IsPickUpPickedUp(int32 pickupId);
+	static int32 ModelForWeapon(eWeaponType weaponType);
+	static enum eWeaponType WeaponForModel(int32 model);
+	static int32 FindColourIndexForWeaponMI(int32 model);
+	static int32 GetActualPickupIndex(int32 index);
+	static int32 GetNewUniquePickupIndex(int32 slot);
+	static void PassTime(uint32 time);
+	static bool GivePlayerGoodiesWithPickUpMI(int16 modelIndex, int playerIndex);
+	static void Load(uint8 *buf, uint32 size);
+	static void Save(uint8 *buf, uint32 *size);
+
+	static CPickup(&aPickUps)[NUMPICKUPS];
+
+	// unused
+	static bool &bPickUpcamActivated;
+	static CVehicle *&pPlayerVehicle;
+	static CVector &StaticCamCoors;
+	static uint32 &StaticCamStartTime;
+};
+
+extern uint16 AmmoForWeapon[20];
+extern uint16 AmmoForWeapon_OnStreet[20];
+extern uint16 CostOfWeapon[20];
+
+enum ePacmanPickupType
+{
+	PACMAN_NONE,
+	PACMAN_SCRAMBLE,
+	PACMAN_RACE,
+};
+
+class CPacManPickup
+{
+public:
+	CVector m_vecPosn;
+	CObject *m_pObject;
+	uint8 m_eType;
+
+	void Update();
+};
+
+class CPacManPickups
+{
+	friend CPacManPickup;
+
+	static CPacManPickup aPMPickUps[NUMPACMANPICKUPS];
+	static CVector LastPickUpCoors;
+	static int PillsEatenInRace;
+	static bool bPMActive;
+public:
+	static void Init(void);
+	static void Update(void);
+	static void GeneratePMPickUps(CVector, float, int16, uint8);
+	static void GeneratePMPickUpsForRace(int32);
+	static void GenerateOnePMPickUp(CVector);
+	static void Render(void);
+	static void StartPacManRace(int32);
+	static void StartPacManRecord(void);
+	static uint32 QueryPowerPillsEatenInRace(void);
+	static void ResetPowerPillsEatenInRace(void);
+	static void ClearPMPickUps(void);
+	static void CleanUpPacManStuff(void);
+	static void StartPacManScramble(CVector, float, int16);
+	static uint32 QueryPowerPillsCarriedByPlayer(void);
+	static void ResetPowerPillsCarriedByPlayer(void);
+
+};
diff --git a/src/control/PowerPoints.cpp b/src/control/PowerPoints.cpp
index 4bc773a9..9a74e8d9 100644
--- a/src/control/PowerPoints.cpp
+++ b/src/control/PowerPoints.cpp
@@ -1,22 +1,22 @@
-#include "common.h"
-#include "PowerPoints.h"
-
-// Some cut beta feature
-
-void CPowerPoint::Update()
-{}
-
-void CPowerPoints::Init()
-{}
-
-void CPowerPoints::Update()
-{}
-
-void CPowerPoints::GenerateNewOne(float, float, float, float, float, float, uint8)
-{}
-
-void CPowerPoints::Save(uint8**, uint32*)
-{}
-
-void CPowerPoints::Load(uint8*, uint32)
+#include "common.h"
+#include "PowerPoints.h"
+
+// Some cut beta feature
+
+void CPowerPoint::Update()
+{}
+
+void CPowerPoints::Init()
+{}
+
+void CPowerPoints::Update()
+{}
+
+void CPowerPoints::GenerateNewOne(float, float, float, float, float, float, uint8)
+{}
+
+void CPowerPoints::Save(uint8**, uint32*)
+{}
+
+void CPowerPoints::Load(uint8*, uint32)
 {}
\ No newline at end of file
diff --git a/src/control/PowerPoints.h b/src/control/PowerPoints.h
index d7478076..ee3750cd 100644
--- a/src/control/PowerPoints.h
+++ b/src/control/PowerPoints.h
@@ -1,26 +1,26 @@
-#pragma once
-
-enum
-{
-	POWERPOINT_NONE = 0,
-	POWERPOINT_HEALTH,
-	POWERPOINT_HIDEOUT_INDUSTRIAL,
-	POWERPOINT_HIDEOUT_COMMERCIAL,
-	POWERPOINT_HIDEOUT_SUBURBAN
-};
-
-class CPowerPoint
-{
-public:
-	void Update();
-};
-
-class CPowerPoints
-{
-public:
-	static void Init();
-	static void Update();
-	static void GenerateNewOne(float, float, float, float, float, float, uint8);
-	static void Save(uint8**, uint32*);
-	static void Load(uint8*, uint32);
+#pragma once
+
+enum
+{
+	POWERPOINT_NONE = 0,
+	POWERPOINT_HEALTH,
+	POWERPOINT_HIDEOUT_INDUSTRIAL,
+	POWERPOINT_HIDEOUT_COMMERCIAL,
+	POWERPOINT_HIDEOUT_SUBURBAN
+};
+
+class CPowerPoint
+{
+public:
+	void Update();
+};
+
+class CPowerPoints
+{
+public:
+	static void Init();
+	static void Update();
+	static void GenerateNewOne(float, float, float, float, float, float, uint8);
+	static void Save(uint8**, uint32*);
+	static void Load(uint8*, uint32);
 };
\ No newline at end of file
diff --git a/src/control/Record.cpp b/src/control/Record.cpp
index 7c330311..ca4128e3 100644
--- a/src/control/Record.cpp
+++ b/src/control/Record.cpp
@@ -2,18 +2,522 @@
 #include "patcher.h"
 #include "Record.h"
 
+#include "FileMgr.h"
+#include "Pad.h"
+#include "Pools.h"
+#include "Streaming.h"
+#include "Timer.h"
+#include "VehicleModelInfo.h"
+#include "World.h"
+
 uint16 &CRecordDataForGame::RecordingState = *(uint16*)0x95CC24;
+uint8*& CRecordDataForGame::pDataBuffer = *(uint8**)0x8F1B70;
+uint8*& CRecordDataForGame::pDataBufferPointer = *(uint8**)0x8F1AB0;
+int& CRecordDataForGame::FId = *(int*)0x885BA4;
+tGameBuffer& CRecordDataForGame::pDataBufferForFrame = *(tGameBuffer*)0x72CED0;
 
-uint8 &CRecordDataForChase::Status = *(uint8*)0x95CDCE;
+#define MEMORY_FOR_GAME_RECORD (150000)
 
-WRAPPER void CRecordDataForGame::SaveOrRetrieveDataForThisFrame(void) { EAXJMP(0x4341F0); }
-WRAPPER void CRecordDataForGame::Init(void) { EAXJMP(0x4340F0); }
+void CRecordDataForGame::Init(void)
+{
+	RecordingState = STATE_NONE;
+	delete[] pDataBuffer;
+	pDataBufferPointer = nil;
+	pDataBuffer = nil;
+#ifndef GTA_PS2 // this stuff is not present on PS2
+	FId = CFileMgr::OpenFile("playback.dat", "r");
+	if (FId <= 0) {
+		if ((FId = CFileMgr::OpenFile("record.dat", "r")) <= 0)
+			RecordingState = STATE_NONE;
+		else {
+			CFileMgr::CloseFile(FId);
+			FId = CFileMgr::OpenFileForWriting("record.dat");
+			RecordingState = STATE_RECORD;
+		}
+	}
+	else {
+		RecordingState = STATE_PLAYBACK;
+	}
+	if (RecordingState == STATE_PLAYBACK) {
+		pDataBufferPointer = new uint8[MEMORY_FOR_GAME_RECORD];
+		pDataBuffer = pDataBufferPointer;
+		pDataBuffer[CFileMgr::Read(FId, (char*)pDataBufferPointer, MEMORY_FOR_GAME_RECORD) + 8] = (uint8)-1;
+		CFileMgr::CloseFile(FId);
+	}
+#else
+	RecordingState = STATE_NONE; // second time to make sure
+#endif
+}
+
+void CRecordDataForGame::SaveOrRetrieveDataForThisFrame(void)
+{
+	switch (RecordingState) {
+	case STATE_RECORD:
+	{
+		pDataBufferForFrame.m_fTimeStep = CTimer::GetTimeStep();
+		pDataBufferForFrame.m_nTimeInMilliseconds = CTimer::GetTimeInMilliseconds();
+		pDataBufferForFrame.m_nSizeOfPads[0] = 0;
+		pDataBufferForFrame.m_nSizeOfPads[1] = 0;
+		pDataBufferForFrame.m_nChecksum = CalcGameChecksum();
+		uint8* pController1 = PackCurrentPadValues(pDataBufferForFrame.m_ControllerBuffer, &CPad::GetPad(0)->OldState, &CPad::GetPad(0)->NewState);
+		pDataBufferForFrame.m_nSizeOfPads[0] = (pController1 - pDataBufferForFrame.m_ControllerBuffer) / 2;
+		uint8* pController2 = PackCurrentPadValues(pController1, &CPad::GetPad(1)->OldState, &CPad::GetPad(1)->NewState);
+		pDataBufferForFrame.m_nSizeOfPads[1] = (pController2 - pController1) / 2;
+		uint8* pEndPtr = pController2;
+		if ((pDataBufferForFrame.m_nSizeOfPads[0] + pDataBufferForFrame.m_nSizeOfPads[1]) & 1)
+			pEndPtr += 2;
+		CFileMgr::Write(FId, (char*)&pDataBufferForFrame, pEndPtr - (uint8*)&pDataBufferForFrame);
+		break;
+	}
+	case STATE_PLAYBACK:
+		if (pDataBufferPointer[8] == (uint8)-1)
+			CPad::GetPad(0)->NewState.Clear();
+		else {
+			tGameBuffer* pData = (tGameBuffer*)pDataBufferPointer;
+			CTimer::SetTimeInMilliseconds(pData->m_nTimeInMilliseconds);
+			CTimer::SetTimeStep(pData->m_fTimeStep);
+			uint8 size1 = pData->m_nSizeOfPads[0];
+			uint8 size2 = pData->m_nSizeOfPads[1];
+			pDataBufferPointer = (uint8*)&pData->m_ControllerBuffer;
+			pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size1, &CPad::GetPad(0)->NewState);
+			pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size2, &CPad::GetPad(1)->NewState);
+			if ((size1 + size2) & 1)
+				pDataBufferPointer += 2;
+			if (pData->m_nChecksum != CalcGameChecksum())
+				printf("Playback out of sync\n");
+		}
+	}
+}
+
+#define PROCESS_BUTTON_STATE_STORE(buf, os, ns, field, id) \
+	do { \
+		if (os->field != ns->field){ \
+			*buf++ = id; \
+			*buf++ = ns->field; \
+		} \
+	} while (0);
+
+uint8* CRecordDataForGame::PackCurrentPadValues(uint8* buf, CControllerState* os, CControllerState* ns)
+{
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickX, 0);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickY, 1);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickX, 2);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickY, 3);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder1, 4);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder2, 5);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder1, 6);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder2, 7);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadUp, 8);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadDown, 9);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadLeft, 10);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadRight, 11);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, Start, 12);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, Select, 13);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, Square, 14);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, Triangle, 15);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, Cross, 16);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, Circle, 17);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShock, 18);
+	PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShock, 19);
+	return buf;
+}
+#undef PROCESS_BUTTON_STATE_STORE
+
+#define PROCESS_BUTTON_STATE_RESTORE(buf, state, field, id) case id: state->field = *buf++; break;
+
+uint8* CRecordDataForGame::UnPackCurrentPadValues(uint8* buf, uint8 total, CControllerState* state)
+{
+	for (uint8 i = 0; i < total; i++) {
+		switch (*buf++) {
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickX, 0);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickY, 1);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickX, 2);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickY, 3);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder1, 4);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder2, 5);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder1, 6);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder2, 7);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadUp, 8);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadDown, 9);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadLeft, 10);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadRight, 11);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, Start, 12);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, Select, 13);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, Square, 14);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, Triangle, 15);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, Cross, 16);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, Circle, 17);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShock, 18);
+			PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShock, 19);
+		}
+	}
+	return buf;
+}
+
+#undef PROCESS_BUTTON_STATE_RESTORE
+
+uint16 CRecordDataForGame::CalcGameChecksum(void)
+{
+	uint32 checksum = 0;
+	int i = CPools::GetPedPool()->GetSize();
+	while (i--) {
+		CPed* pPed = CPools::GetPedPool()->GetSlot(i);
+		if (!pPed)
+			continue;
+		checksum ^= pPed->GetModelIndex() ^ *(uint32*)&pPed->GetPosition().z ^ *(uint32*)&pPed->GetPosition().y ^ *(uint32*)&pPed->GetPosition().x;
+	}
+	i = CPools::GetVehiclePool()->GetSize();
+	while (i--) {
+		CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+		if (!pVehicle)
+			continue;
+		checksum ^= pVehicle->GetModelIndex() ^ *(uint32*)&pVehicle->GetPosition().z ^ *(uint32*)&pVehicle->GetPosition().y ^ *(uint32*)&pVehicle->GetPosition().x;
+	}
+	return checksum ^ checksum >> 16;
+}
+
+uint8& CRecordDataForChase::Status = *(uint8*)0x95CDCE;
+int& CRecordDataForChase::PositionChanges = *(int*)0x8F59C8;
+uint8& CRecordDataForChase::CurrentCar = *(uint8*)0x95CDC9;
+CAutomobile* (&CRecordDataForChase::pChaseCars)[NUM_CHASE_CARS] = *(CAutomobile * (*)[NUM_CHASE_CARS])*(uintptr*)0x6F46A8;
+uint32& CRecordDataForChase::AnimStartTime = *(uint32*)0x8F1AEC;
+float& CRecordDataForChase::AnimTime = *(float*)0x880F88;
+CCarStateEachFrame* (&CRecordDataForChase::pBaseMemForCar)[NUM_CHASE_CARS] = *(CCarStateEachFrame * (*)[NUM_CHASE_CARS])*(uintptr*)0x70EA18;
+float& CRecordDataForChase::TimeMultiplier = *(float*)0x8E2A94;
+int& CRecordDataForChase::FId2 = *(int*)0x8E2C18;
+
+#define CHASE_SCENE_LENGTH_IN_SECONDS (80)
+#define CHASE_SCENE_FRAMES_PER_SECOND (15) // skipping every second frame
+#define CHASE_SCENE_FRAMES_IN_RECORDING (CHASE_SCENE_LENGTH_IN_SECONDS * CHASE_SCENE_FRAMES_PER_SECOND)
+#define CHASE_SCENE_LENGTH_IN_FRAMES (CHASE_SCENE_FRAMES_IN_RECORDING * 2)
+
+void CRecordDataForChase::Init(void)
+{
+	Status = STATE_NONE;
+	PositionChanges = 0;
+	CurrentCar = 0;
+	for (int i = 0; i < NUM_CHASE_CARS; i++)
+		pChaseCars[i] = nil;
+	AnimStartTime = 0;
+}
+
+void CRecordDataForChase::SaveOrRetrieveDataForThisFrame(void)
+{
+	switch (Status) {
+	case STATE_NONE:
+		return;
+	case STATE_RECORD:
+	{
+		if ((CTimer::GetFrameCounter() & 1) == 0)
+			StoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2]);
+		if (CTimer::GetFrameCounter() < CHASE_SCENE_LENGTH_IN_FRAMES * 2)
+			return;
+		CFileMgr::SetDir("data\\paths");
+		sprintf(gString, "chase%d.dat", CurrentCar);
+		int fid = CFileMgr::OpenFileForWriting(gString);
+		uint32 fs = CHASE_SCENE_LENGTH_IN_FRAMES * sizeof(CCarStateEachFrame);
+		printf("FileSize:%d\n", fs);
+		CFileMgr::Write(fid, (char*)pBaseMemForCar[CurrentCar], fs);
+		CFileMgr::CloseFile(fid);
+		CFileMgr::SetDir("");
+		sprintf(gString, "car%d.max", CurrentCar);
+		int fid2 = CFileMgr::OpenFileForWriting(gString);
+		for (int i = 0; i < CHASE_SCENE_FRAMES_IN_RECORDING; i++) {
+			// WTF? Was it ever used?
+#ifdef FIX_BUGS
+			CCarStateEachFrame* pState = pBaseMemForCar[CurrentCar];
+#else
+			CCarStateEachFrame* pState = (CCarStateEachFrame*)pChaseCars[CurrentCar];
+#endif
+			CVector right = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX;
+			CVector forward = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX;
+			CVector up = CrossProduct(right, forward);
+			sprintf(gString, "%f %f %f\n", pState->pos.x, pState->pos.y, pState->pos.z);
+			CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+			sprintf(gString, "%f %f %f\n", right.x, right.y, right.z);
+			CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+			sprintf(gString, "%f %f %f\n", forward.x, forward.y, forward.z);
+			CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+			sprintf(gString, "%f %f %f\n", up.x, up.y, up.z);
+			CFileMgr::Write(fid2, gString, strlen(gString) - 1);
+		}
+		CFileMgr::CloseFile(fid2);
+	}
+	case STATE_PLAYBACK:
+	case STATE_PLAYBACK_BEFORE_RECORDING:
+	case STATE_PLAYBACK_INIT:
+		break;
+	}
+}
+
+struct tCoors {
+	CVector pos;
+	float angle;
+};
+
+// I guess developer was filling this with actual data before running the game
+tCoors NewCoorsForRecordedCars[7];
+
+void CRecordDataForChase::SaveOrRetrieveCarPositions(void)
+{
+	switch (Status) {
+	case STATE_NONE:
+		return;
+	case STATE_RECORD:
+	case STATE_PLAYBACK_BEFORE_RECORDING:
+		for (int i = 0; i < NUM_CHASE_CARS; i++) {
+			if (i != CurrentCar && CTimer::GetFrameCounter()) {
+				RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CTimer::GetFrameCounter() / 2], false);
+				pChaseCars[i]->GetMatrix().UpdateRW();
+				pChaseCars[i]->UpdateRwFrame();
+			}
+		}
+		if (Status == STATE_PLAYBACK_BEFORE_RECORDING && CTimer::GetFrameCounter()) {
+			RestoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2], false);
+			pChaseCars[CurrentCar]->GetMatrix().UpdateRW();
+			pChaseCars[CurrentCar]->UpdateRwFrame();
+		}
+		if (CPad::GetPad(0)->GetLeftShockJustDown() && CPad::GetPad(0)->GetRightShockJustDown()) {
+			if (!CPad::GetPad(0)->GetRightShockJustDown()) {
+				pChaseCars[CurrentCar]->GetPosition() = NewCoorsForRecordedCars[PositionChanges].pos;
+				pChaseCars[CurrentCar]->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+				pChaseCars[CurrentCar]->GetMatrix().SetRotateZOnly(DEGTORAD(NewCoorsForRecordedCars[PositionChanges].angle));
+				++PositionChanges;
+			}
+			if (Status == STATE_PLAYBACK_BEFORE_RECORDING) {
+				Status = STATE_RECORD;
+				pChaseCars[CurrentCar]->m_status = STATUS_PLAYER;
+			}
+		}
+		break;
+	case STATE_PLAYBACK_INIT:
+		Status = STATE_PLAYBACK;
+		break;
+	case STATE_PLAYBACK:
+	{
+		TimeMultiplier += CTimer::GetTimeStepNonClippedInSeconds();
+		float EndOfFrameTime = CHASE_SCENE_FRAMES_PER_SECOND * min(CHASE_SCENE_LENGTH_IN_SECONDS, TimeMultiplier);
+		for (int i = 0; i < NUM_CHASE_CARS; i++) {
+			if (!pBaseMemForCar[i])
+				continue;
+			if (!pChaseCars[i])
+				continue;
+			if (EndOfFrameTime < CHASE_SCENE_FRAMES_IN_RECORDING - 1) {
+				int FlooredEOFTime = EndOfFrameTime;
+				RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][FlooredEOFTime], false);
+				CMatrix tmp;
+				float dp = EndOfFrameTime - FlooredEOFTime;
+				RestoreInfoForMatrix(tmp, &pBaseMemForCar[i][FlooredEOFTime + 1]);
+				pChaseCars[i]->GetRight() += (tmp.GetRight() - pChaseCars[i]->GetRight()) * dp;
+				pChaseCars[i]->GetForward() += (tmp.GetForward() - pChaseCars[i]->GetForward()) * dp;
+				pChaseCars[i]->GetUp() += (tmp.GetUp() - pChaseCars[i]->GetUp()) * dp;
+				pChaseCars[i]->GetPosition() += (tmp.GetPosition() - pChaseCars[i]->GetPosition()) * dp;
+			}
+			else{
+				RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CHASE_SCENE_FRAMES_IN_RECORDING - 1], true);
+				if (i == 0)
+					pChaseCars[i]->GetPosition().z += 0.2f;
+			}
+			pChaseCars[i]->GetMatrix().UpdateRW();
+			pChaseCars[i]->UpdateRwFrame();
+			pChaseCars[i]->RemoveAndAdd();
+		}
+		break;
+	}
+	}
+}
+
+void CRecordDataForChase::StoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState)
+{
+	pState->rightX = INT8_MAX * pCar->GetRight().x;
+	pState->rightY = INT8_MAX * pCar->GetRight().y;
+	pState->rightZ = INT8_MAX * pCar->GetRight().z;
+	pState->forwardX = INT8_MAX * pCar->GetForward().x;
+	pState->forwardY = INT8_MAX * pCar->GetForward().y;
+	pState->forwardZ = INT8_MAX * pCar->GetForward().z;
+	pState->pos = pCar->GetPosition();
+	pState->velX = 0.5f * INT16_MAX * pCar->GetMoveSpeed().x;
+	pState->velY = 0.5f * INT16_MAX * pCar->GetMoveSpeed().y;
+	pState->velZ = 0.5f * INT16_MAX * pCar->GetMoveSpeed().z;
+	pState->wheel = 20 * pCar->m_fSteerAngle;
+	pState->gas = 100 * pCar->m_fGasPedal;
+	pState->brake = 100 * pCar->m_fBrakePedal;
+	pState->handbrake = pCar->bIsHandbrakeOn;
+}
+
+void CRecordDataForChase::RestoreInfoForMatrix(CMatrix& matrix, CCarStateEachFrame* pState)
+{
+	matrix.GetRight() = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX;
+	matrix.GetForward() = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX;
+	matrix.GetUp() = CrossProduct(matrix.GetRight(), matrix.GetForward());
+	matrix.GetPosition() = pState->pos;
+}
+
+void CRecordDataForChase::RestoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState, bool stop)
+{
+	CVector oldPos = pCar->GetPosition();
+	RestoreInfoForMatrix(pCar->GetMatrix(), pState);
+	pCar->SetMoveSpeed(CVector(pState->velX, pState->velY, pState->velZ) / INT16_MAX / 0.5f);
+	pCar->SetTurnSpeed(0.0f, 0.0f, 0.0f);
+	pCar->m_fSteerAngle = pState->wheel / 20.0f;
+	pCar->m_fGasPedal = pState->gas / 100.0f;
+	pCar->m_fBrakePedal = pState->brake / 100.0f;
+	pCar->bIsHandbrakeOn = pState->handbrake;
+	if ((oldPos - pCar->GetPosition()).Magnitude() > 15.0f) {
+		if (pCar == pChaseCars[14]) {
+			pCar->m_currentColour1 = 58;
+			pCar->m_currentColour2 = 1;
+		}
+		else
+			pCar->GetModelInfo()->ChooseVehicleColour(pCar->m_currentColour1, pCar->m_currentColour2);
+	}
+	pCar->m_fHealth = min(pCar->m_fHealth, 500.0f);
+	if (stop) {
+		pCar->m_fGasPedal = 0.0f;
+		pCar->m_fBrakePedal = 0.0f;
+		pCar->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+		pCar->bIsHandbrakeOn = false;
+	}
+}
+
+void CRecordDataForChase::ProcessControlCars(void)
+{
+	if (Status != STATE_PLAYBACK)
+		return;
+	for (int i = 0; i < NUM_CHASE_CARS; i++) {
+		if (pChaseCars[i])
+			pChaseCars[i]->ProcessControl();
+	}
+}
+
+#if (defined(GTA_PS2) || defined(FIX_BUGS))
+bool CRecordDataForChase::ShouldThisPadBeLeftAlone(uint8 pad)
+{
+	// may be wrong
+	if (Status == STATE_NONE || Status == STATE_PLAYBACK)
+		return false;
+	return pad != 0;
+}
+#endif
+
+void CRecordDataForChase::GiveUsACar(int32 mi, CVector pos, float angle, CAutomobile** ppCar, uint8 colour1, uint8 colour2)
+{
+	CStreaming::RequestModel(mi, STREAMFLAGS_DEPENDENCY);
+	CStreaming::LoadAllRequestedModels(false);
+	if (!CStreaming::HasModelLoaded(mi))
+		return;
+	CAutomobile* pCar = new CAutomobile(mi, MISSION_VEHICLE);
+	pCar->GetPosition() = pos;
+	pCar->m_status = STATUS_PLAYER_PLAYBACKFROMBUFFER;
+	pCar->GetMatrix().SetRotateZOnly(DEGTORAD(angle));
+	pCar->pDriver = nil;
+	pCar->m_currentColour1 = colour1;
+	pCar->m_currentColour2 = colour2;
+	CWorld::Add(pCar);
+	*ppCar = pCar;
+}
+
+void RemoveUnusedCollision(void)
+{
+	static const char* dontDeleteArray[] = {
+		"rd_SrRoad2A50", "rd_SrRoad2A20", "rd_CrossRda1w22", "rd_CrossRda1rw22",
+		"road_broadway02", "road_broadway01", "com_21way5", "com_21way50",
+		"cm1waycrosscom", "com_21way20", "com_21way10", "road_broadway04",
+		"com_rvroads52", "com_roadsrv", "com_roadkb23", "com_roadkb22"
+	};
+	for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++)
+		CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_NONE;
+	CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_NONE);
+	for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++)
+		CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_COMMERCIAL;
+}
+
+void CRecordDataForChase::StartChaseScene(float startTime)
+{
+	char filename[28];
+	SetUpCarsForChaseScene();
+	Status = STATE_PLAYBACK;
+	AnimTime = startTime;
+	AnimStartTime = CTimer::GetTimeInMilliseconds();
+	RemoveUnusedCollision();
+	CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN);
+	CGame::TidyUpMemory(true, true);
+	CStreaming::ImGonnaUseStreamingMemory();
+	CFileMgr::SetDir("data\\paths");
+	for (int i = 0; i < NUM_CHASE_CARS; i++) {
+		if (!pChaseCars[i]) {
+			pBaseMemForCar[i] = nil;
+			continue;
+		}
+		sprintf(filename, "chase%d.dat", i);
+		FId2 = CFileMgr::OpenFile(filename, "rb");
+		if (FId2 <= 0) {
+			pBaseMemForCar[i] = nil;
+			continue;
+		}
+		pBaseMemForCar[i] = new CCarStateEachFrame[CHASE_SCENE_FRAMES_IN_RECORDING];
+		for (int j = 0; j < CHASE_SCENE_FRAMES_IN_RECORDING; j++) {
+			CFileMgr::Read(FId2, (char*)&pBaseMemForCar[i][j], sizeof(CCarStateEachFrame));
+			CFileMgr::Seek(FId2, sizeof(CCarStateEachFrame), 1);
+		}
+		CFileMgr::CloseFile(FId2);
+	}
+	CFileMgr::SetDir("");
+	CStreaming::IHaveUsedStreamingMemory();
+	TimeMultiplier = 0.0f;
+}
+
+void CRecordDataForChase::CleanUpChaseScene(void)
+{
+	if (Status != STATE_PLAYBACK_INIT && Status != STATE_PLAYBACK)
+		return;
+	Status = STATE_NONE;
+	CleanUpCarsForChaseScene();
+	for (int i = 0; i < NUM_CHASE_CARS; i++) {
+		if (pBaseMemForCar[i]) {
+			delete[] pBaseMemForCar[i];
+			pBaseMemForCar[i] = nil;
+		}
+	}
+}
+
+void CRecordDataForChase::SetUpCarsForChaseScene(void)
+{
+	GiveUsACar(MI_POLICE, CVector(273.54221f, -1167.1907f, 24.880601f), 63.0f, &pChaseCars[0], 2, 1);
+	GiveUsACar(MI_ENFORCER, CVector(231.1783f, -1388.8322f, 25.978201f), 90.0f, &pChaseCars[1], 2, 1);
+	GiveUsACar(MI_TAXI, CVector(184.3156f, -1473.251f, 25.978201f), 0.0f, &pChaseCars[4], 6, 6);
+	GiveUsACar(MI_CHEETAH, CVector(173.8868f, -1377.6514f, 25.978201f), 0.0f, &pChaseCars[6], 4, 5);
+	GiveUsACar(MI_STINGER, CVector(102.5946f, -943.93628f, 25.9781f), 270.0f, &pChaseCars[7], 53, 53);
+	GiveUsACar(MI_CHEETAH, CVector(-177.7157f, -862.18652f, 25.978201f), 155.0f, &pChaseCars[10], 41, 1);
+	GiveUsACar(MI_STINGER, CVector(-170.56979f, -889.02362f, 25.978201f), 154.0f, &pChaseCars[11], 10, 10);
+	GiveUsACar(MI_KURUMA, CVector(402.60809f, -917.49628f, 37.381001f), 90.0f, &pChaseCars[14], 34, 1);
+	GiveUsACar(MI_TAXI, CVector(-33.496201f, -938.4563f, 25.9781f), 266.0f, &pChaseCars[16], 6, 6);
+	GiveUsACar(MI_KURUMA, CVector(49.363098f, -987.60498f, 25.9781f), 0.0f, &pChaseCars[18], 51, 1);
+	GiveUsACar(MI_TAXI, CVector(179.0049f, -1154.6686f, 25.9781f), 0.0f, &pChaseCars[19], 6, 76);
+	GiveUsACar(MI_RUMPO, CVector(-28.9762f, -1031.3367f, 25.990601f), 242.0f, &pChaseCars[2], 1, 75);
+	GiveUsACar(MI_PATRIOT, CVector(114.1564f, -796.69379f, 24.978201f), 180.0f, &pChaseCars[3], 0, 0);
+}
+
+void CRecordDataForChase::CleanUpCarsForChaseScene(void)
+{
+	for (int i = 0; i < NUM_CHASE_CARS; i++)
+		RemoveCarFromChase(i);
+}
+
+void CRecordDataForChase::RemoveCarFromChase(int32 i)
+{
+	if (!pChaseCars[i])
+		return;
+	CWorld::Remove(pChaseCars[i]);
+	delete pChaseCars[i];
+	pChaseCars[i] = nil;
+}
+
+CVehicle* CRecordDataForChase::TurnChaseCarIntoScriptCar(int32 i)
+{
+	CVehicle* pVehicle = pChaseCars[i];
+	pChaseCars[i] = nil;
+	pVehicle->m_status = STATUS_PHYSICS;
+	return pVehicle;
+}
 
-WRAPPER void CRecordDataForChase::SaveOrRetrieveDataForThisFrame(void) { EAXJMP(0x4347F0); }
-WRAPPER void CRecordDataForChase::ProcessControlCars(void) { EAXJMP(0x435540); }
-WRAPPER void CRecordDataForChase::SaveOrRetrieveCarPositions(void) { EAXJMP(0x434B20); }
-WRAPPER void CRecordDataForChase::StartChaseScene(float) { EAXJMP(0x435690); }
-WRAPPER void CRecordDataForChase::CleanUpChaseScene() { EAXJMP(0x4357C0); }
-WRAPPER void CRecordDataForChase::RemoveCarFromChase(int32) { EAXJMP(0x435BC0); }
-WRAPPER CVehicle* CRecordDataForChase::TurnChaseCarIntoScriptCar(int32) { EAXJMP(0x435C00); }
-WRAPPER void CRecordDataForChase::Init(void) { EAXJMP(0x434780); }
diff --git a/src/control/Record.h b/src/control/Record.h
index e52a623e..4abeb68a 100644
--- a/src/control/Record.h
+++ b/src/control/Record.h
@@ -1,34 +1,106 @@
 #pragma once
 
+class CAutomobile;
 class CVehicle;
+class CControllerState;
 
-enum {
-	RECORDSTATE_0,
-	RECORDSTATE_1,
-	RECORDSTATE_2,
+class CCarStateEachFrame
+{
+public:
+	int16 velX;
+	int16 velY;
+	int16 velZ;
+	int8 rightX;
+	int8 rightY;
+	int8 rightZ;
+	int8 forwardX;
+	int8 forwardY;
+	int8 forwardZ;
+	int8 wheel;
+	uint8 gas;
+	uint8 brake;
+	bool handbrake;
+	CVector pos;
 };
 
+extern char* gString;
+
 class CRecordDataForChase
 {
-public:
+	enum {
+		NUM_CHASE_CARS = 20
+	};
+	enum {
+		STATE_NONE = 0,
+		STATE_RECORD = 1,
+		STATE_PLAYBACK_INIT = 2,
+		STATE_PLAYBACK = 3,
+		STATE_PLAYBACK_BEFORE_RECORDING = 4
+	};
 	static uint8 &Status;
+	static int &PositionChanges;
+	static uint8 &CurrentCar;
+	static CAutomobile*(&pChaseCars)[NUM_CHASE_CARS];
+	static float &AnimTime;
+	static uint32 &AnimStartTime;
+	static CCarStateEachFrame* (&pBaseMemForCar)[NUM_CHASE_CARS];
+	static float &TimeMultiplier;
+	static int &FId2;
+public:
 
+	static bool IsRecording(void) { return Status == STATE_RECORD; }
+
+	static void Init(void);
 	static void SaveOrRetrieveDataForThisFrame(void);
-	static void ProcessControlCars(void);
 	static void SaveOrRetrieveCarPositions(void);
+	static void StoreInfoForCar(CAutomobile*, CCarStateEachFrame*);
+	static void RestoreInfoForMatrix(CMatrix&, CCarStateEachFrame*);
+	static void RestoreInfoForCar(CAutomobile*, CCarStateEachFrame*, bool);
+	static void ProcessControlCars(void);
+#if (defined(GTA_PS2) || defined(FIX_BUGS))
+	static bool ShouldThisPadBeLeftAlone(uint8 pad);
+#endif
+	static void GiveUsACar(int32, CVector, float, CAutomobile**, uint8, uint8);
 	static void StartChaseScene(float);
-	static void CleanUpChaseScene();
+	static void CleanUpChaseScene(void);
+	static void SetUpCarsForChaseScene(void);
+	static void CleanUpCarsForChaseScene(void);
 	static void RemoveCarFromChase(int32);
 	static CVehicle* TurnChaseCarIntoScriptCar(int32);
-	static void Init(void);
+
 };
 
+struct tGameBuffer
+{
+	float m_fTimeStep;
+	uint32 m_nTimeInMilliseconds;
+	uint8 m_nSizeOfPads[2];
+	uint16 m_nChecksum;
+	uint8 m_ControllerBuffer[116];
+};
 
 class CRecordDataForGame
 {
+	enum {
+		STATE_NONE = 0,
+		STATE_RECORD = 1,
+		STATE_PLAYBACK = 2,
+	};
+	static uint16& RecordingState;
+	static uint8* &pDataBuffer;
+	static uint8* &pDataBufferPointer;
+	static int &FId;
+	static tGameBuffer &pDataBufferForFrame;
+
 public:
-	static uint16 &RecordingState;
+	static bool IsRecording() { return RecordingState == STATE_RECORD; }
+	static bool IsPlayingBack() { return RecordingState == STATE_PLAYBACK; }
 
 	static void SaveOrRetrieveDataForThisFrame(void);
 	static void Init(void);
+
+private:
+	static uint16 CalcGameChecksum(void);
+	static uint8* PackCurrentPadValues(uint8*, CControllerState*, CControllerState*);
+	static uint8* UnPackCurrentPadValues(uint8*, uint8, CControllerState*);
 };
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 2e325249..0da32dd2 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -1107,7 +1107,7 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca
 		CStreaming::LoadScene(ff_coord);
 	}
 	if (cam_mode == REPLAYCAMMODE_ASSTORED)
-		TheCamera.CarZoomIndicator = 5.0f;
+		TheCamera.CarZoomIndicator = CAM_ZOOM_CINEMATIC;
 }
 
 void CReplay::StoreStuffInMem(void)
@@ -1129,8 +1129,8 @@ void CReplay::StoreStuffInMem(void)
 	pEmptyReferences = CReferences::pEmptyList;
 	pStoredCam = new uint8[sizeof(CCamera)];
 	memcpy(pStoredCam, &TheCamera, sizeof(CCamera));
-	pRadarBlips = new uint8[sizeof(CBlip) * NUMRADARBLIPS];
-	memcpy(pRadarBlips, CRadar::ms_RadarTrace, NUMRADARBLIPS * sizeof(CBlip));
+	pRadarBlips = new uint8[sizeof(sRadarTrace) * NUMRADARBLIPS];
+	memcpy(pRadarBlips, CRadar::ms_RadarTrace, NUMRADARBLIPS * sizeof(sRadarTrace));
 	PlayerWanted = *FindPlayerPed()->m_pWanted;
 	PlayerInfo = CWorld::Players[0];
 	Time1 = CTimer::GetTimeInMilliseconds();
@@ -1179,7 +1179,7 @@ void CReplay::RestoreStuffFromMem(void)
 	memcpy(&TheCamera, pStoredCam, sizeof(CCamera));
 	delete[] pStoredCam;
 	pStoredCam = nil;
-	memcpy(CRadar::ms_RadarTrace, pRadarBlips, sizeof(CBlip) * NUMRADARBLIPS);
+	memcpy(CRadar::ms_RadarTrace, pRadarBlips, sizeof(sRadarTrace) * NUMRADARBLIPS);
 	delete[] pRadarBlips;
 	pRadarBlips = nil;
 	FindPlayerPed()->m_pWanted = new CWanted(PlayerWanted);
diff --git a/src/control/Restart.cpp b/src/control/Restart.cpp
index 8e983555..788a054a 100644
--- a/src/control/Restart.cpp
+++ b/src/control/Restart.cpp
@@ -21,234 +21,234 @@ CVector(&CRestart::PoliceRestartPoints)[NUM_RESTART_POINTS] = *(CVector(*)[NUM_R
 float(&CRestart::PoliceRestartHeadings)[NUM_RESTART_POINTS] = *(float(*)[NUM_RESTART_POINTS])*(uintptr*)0x6F1D20;
 uint16 &CRestart::NumberOfPoliceRestarts = *(uint16*)0x95CC44;
 
-void
-CRestart::Initialise()
-{
-	OverridePoliceStationLevel = LEVEL_NONE;
-	OverrideHospitalLevel = LEVEL_NONE;
-	bFadeInAfterNextArrest = true;
-	bFadeInAfterNextDeath = true;
-	OverrideHeading = 0.0f;
-	OverridePosition = CVector(0.0f, 0.0f, 0.0f);
-	bOverrideRestart = false;
-	NumberOfPoliceRestarts = 0;
-	NumberOfHospitalRestarts = 0;
-
-	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
-		HospitalRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
-		HospitalRestartHeadings[i] = 0.0f;
-		PoliceRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
-		PoliceRestartHeadings[i] = 0.0f;
-	}
+void
+CRestart::Initialise()
+{
+	OverridePoliceStationLevel = LEVEL_NONE;
+	OverrideHospitalLevel = LEVEL_NONE;
+	bFadeInAfterNextArrest = true;
+	bFadeInAfterNextDeath = true;
+	OverrideHeading = 0.0f;
+	OverridePosition = CVector(0.0f, 0.0f, 0.0f);
+	bOverrideRestart = false;
+	NumberOfPoliceRestarts = 0;
+	NumberOfHospitalRestarts = 0;
+
+	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+		HospitalRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
+		HospitalRestartHeadings[i] = 0.0f;
+		PoliceRestartPoints[i] = CVector(0.0f, 0.0f, 0.0f);
+		PoliceRestartHeadings[i] = 0.0f;
+	}
 }
 
-void
-CRestart::AddHospitalRestartPoint(const CVector &pos, float heading)
-{
-	HospitalRestartPoints[NumberOfHospitalRestarts] = pos;
-	HospitalRestartHeadings[NumberOfHospitalRestarts++] = heading;
+void
+CRestart::AddHospitalRestartPoint(const CVector &pos, float heading)
+{
+	HospitalRestartPoints[NumberOfHospitalRestarts] = pos;
+	HospitalRestartHeadings[NumberOfHospitalRestarts++] = heading;
 }
 
-void
-CRestart::AddPoliceRestartPoint(const CVector &pos, float heading)
-{
-	PoliceRestartPoints[NumberOfPoliceRestarts] = pos;
-	PoliceRestartHeadings[NumberOfPoliceRestarts++] = heading;
+void
+CRestart::AddPoliceRestartPoint(const CVector &pos, float heading)
+{
+	PoliceRestartPoints[NumberOfPoliceRestarts] = pos;
+	PoliceRestartHeadings[NumberOfPoliceRestarts++] = heading;
 }
 
-void
-CRestart::OverrideNextRestart(const CVector &pos, float heading)
-{
-	bOverrideRestart = true;
-	OverridePosition = pos;
-	OverrideHeading = heading;
+void
+CRestart::OverrideNextRestart(const CVector &pos, float heading)
+{
+	bOverrideRestart = true;
+	OverridePosition = pos;
+	OverrideHeading = heading;
 }
 
-void
-CRestart::CancelOverrideRestart()
-{
-	bOverrideRestart = false;
+void
+CRestart::CancelOverrideRestart()
+{
+	bOverrideRestart = false;
 }
 
-void
-CRestart::FindClosestHospitalRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
-{
-	if (bOverrideRestart) {
-		*outPos = OverridePosition;
-		*outHeading = OverrideHeading;
-		CancelOverrideRestart();
-		return;
-	}
-
-	eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
-	float fMinDist = 16000000.0f;
-	int closestPoint = NUM_RESTART_POINTS;
-
-	// find closest point on this level
-	for (int i = 0; i < NumberOfHospitalRestarts; i++) {
-		if (CTheZones::FindZoneForPoint(HospitalRestartPoints[i]) == (OverrideHospitalLevel != LEVEL_NONE ? OverrideHospitalLevel : curlevel)) {
-			float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
-			if (fMinDist >= dist) {
-				fMinDist = dist;
-				closestPoint = i;
-			}
-		}
-	}
-
-	// if we didn't find anything, find closest point on any level
-	if (closestPoint == NUM_RESTART_POINTS) {
-		for (int i = 0; i < NumberOfHospitalRestarts; i++) {
-			float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
-			if (fMinDist >= dist) {
-				fMinDist = dist;
-				closestPoint = i;
-			}
-		}
-	}
-
-	// if we still didn't find anything, find closest path node
-	if (closestPoint == NUM_RESTART_POINTS) {
-		*outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
-		*outHeading = 0.0f;
-		printf("Couldn't find a hospital restart zone near the player %f %f %f->%f %f %f\n", pos.x, pos.y, pos.z, outPos->x, outPos->y, outPos->z);
-	} else {
-		*outPos = HospitalRestartPoints[closestPoint];
-		*outHeading = HospitalRestartHeadings[closestPoint];
-	}
+void
+CRestart::FindClosestHospitalRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
+{
+	if (bOverrideRestart) {
+		*outPos = OverridePosition;
+		*outHeading = OverrideHeading;
+		CancelOverrideRestart();
+		return;
+	}
+
+	eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
+	float fMinDist = 16000000.0f;
+	int closestPoint = NUM_RESTART_POINTS;
+
+	// find closest point on this level
+	for (int i = 0; i < NumberOfHospitalRestarts; i++) {
+		if (CTheZones::FindZoneForPoint(HospitalRestartPoints[i]) == (OverrideHospitalLevel != LEVEL_NONE ? OverrideHospitalLevel : curlevel)) {
+			float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
+			if (fMinDist >= dist) {
+				fMinDist = dist;
+				closestPoint = i;
+			}
+		}
+	}
+
+	// if we didn't find anything, find closest point on any level
+	if (closestPoint == NUM_RESTART_POINTS) {
+		for (int i = 0; i < NumberOfHospitalRestarts; i++) {
+			float dist = (pos - HospitalRestartPoints[i]).MagnitudeSqr();
+			if (fMinDist >= dist) {
+				fMinDist = dist;
+				closestPoint = i;
+			}
+		}
+	}
+
+	// if we still didn't find anything, find closest path node
+	if (closestPoint == NUM_RESTART_POINTS) {
+		*outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
+		*outHeading = 0.0f;
+		printf("Couldn't find a hospital restart zone near the player %f %f %f->%f %f %f\n", pos.x, pos.y, pos.z, outPos->x, outPos->y, outPos->z);
+	} else {
+		*outPos = HospitalRestartPoints[closestPoint];
+		*outHeading = HospitalRestartHeadings[closestPoint];
+	}
 }
 
-void
-CRestart::FindClosestPoliceRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
-{
-	if (bOverrideRestart) {
-		*outPos = OverridePosition;
-		*outHeading = OverrideHeading;
-		CancelOverrideRestart();
-		return;
-	}
-
-	eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
-	float fMinDist = 16000000.0f;
-	int closestPoint = NUM_RESTART_POINTS;
-
-	// find closest point on this level
-	for (int i = 0; i < NumberOfPoliceRestarts; i++) {
-		if (CTheZones::FindZoneForPoint(PoliceRestartPoints[i]) == (OverridePoliceStationLevel != LEVEL_NONE ? OverridePoliceStationLevel : curlevel)) {
-			float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
-			if (fMinDist >= dist) {
-				fMinDist = dist;
-				closestPoint = i;
-			}
-		}
-	}
-
-	// if we didn't find anything, find closest point on any level
-	if (closestPoint == NUM_RESTART_POINTS) {
-		for (int i = 0; i < NumberOfPoliceRestarts; i++) {
-			float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
-			if (fMinDist >= dist) {
-				fMinDist = dist;
-				closestPoint = i;
-			}
-		}
-	}
-
-	// if we still didn't find anything, find closest path node
-	if (closestPoint == NUM_RESTART_POINTS) {
-		printf("Couldn't find a police restart zone near the player\n");
-		*outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
-		*outHeading = 0.0f;
-	} else {
-		*outPos = PoliceRestartPoints[closestPoint];
-		*outHeading = PoliceRestartHeadings[closestPoint];
-	}
-}
-
-void
-CRestart::LoadAllRestartPoints(uint8 *buf, uint32 size)
-{
-	Initialise();
-
-INITSAVEBUF
-	CheckSaveHeader(buf, 'R','S','T','\0', size - SAVE_HEADER_SIZE);
-
-	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
-		HospitalRestartPoints[i] = ReadSaveBuf<CVector>(buf);
-		HospitalRestartHeadings[i] = ReadSaveBuf<float>(buf);
-	}
-
-	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
-		PoliceRestartPoints[i] = ReadSaveBuf<CVector>(buf);
-		PoliceRestartHeadings[i] = ReadSaveBuf<float>(buf);
-	}
-
-	NumberOfHospitalRestarts = ReadSaveBuf<uint16>(buf);
-	NumberOfPoliceRestarts = ReadSaveBuf<uint16>(buf);
-	bOverrideRestart = ReadSaveBuf<bool>(buf);
-
-	// skip something unused
-	ReadSaveBuf<uint8>(buf);
-	ReadSaveBuf<uint16>(buf);
-
-	OverridePosition = ReadSaveBuf<CVector>(buf);
-	OverrideHeading = ReadSaveBuf<float>(buf);
-	bFadeInAfterNextDeath = ReadSaveBuf<bool>(buf);
-	bFadeInAfterNextArrest = ReadSaveBuf<bool>(buf);
-	OverrideHospitalLevel = ReadSaveBuf<uint8>(buf);
-	OverridePoliceStationLevel = ReadSaveBuf<uint8>(buf);
-VALIDATESAVEBUF(size);
-}
-
-void
-CRestart::SaveAllRestartPoints(uint8 *buf, uint32 *size)
-{
-	*size = SAVE_HEADER_SIZE
-		+ sizeof(HospitalRestartPoints)
-		+ sizeof(HospitalRestartHeadings)
-		+ sizeof(PoliceRestartPoints)
-		+ sizeof(PoliceRestartHeadings)
-		+ sizeof(NumberOfHospitalRestarts)
-		+ sizeof(NumberOfPoliceRestarts)
-		+ sizeof(bOverrideRestart)
-		+ sizeof(uint8)
-		+ sizeof(uint16)
-		+ sizeof(OverridePosition)
-		+ sizeof(OverrideHeading)
-		+ sizeof(bFadeInAfterNextDeath)
-		+ sizeof(bFadeInAfterNextArrest)
-		+ sizeof(OverrideHospitalLevel)
-		+ sizeof(OverridePoliceStationLevel); // == 292
-
-INITSAVEBUF
-	WriteSaveHeader(buf, 'R','S','T','\0', *size - SAVE_HEADER_SIZE);
-
-	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
-		WriteSaveBuf(buf, HospitalRestartPoints[i]);
-		WriteSaveBuf(buf, HospitalRestartHeadings[i]);
-	}
-
-	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
-		WriteSaveBuf(buf, PoliceRestartPoints[i]);
-		WriteSaveBuf(buf, PoliceRestartHeadings[i]);
-	}
-
-	WriteSaveBuf(buf, NumberOfHospitalRestarts);
-	WriteSaveBuf(buf, NumberOfPoliceRestarts);
-	WriteSaveBuf(buf, bOverrideRestart);
-
-	WriteSaveBuf(buf, (uint8)0);
-	WriteSaveBuf(buf, (uint16)0);
-
-	WriteSaveBuf(buf, OverridePosition);
-	WriteSaveBuf(buf, OverrideHeading);
-	WriteSaveBuf(buf, bFadeInAfterNextDeath);
-	WriteSaveBuf(buf, bFadeInAfterNextArrest);
-	WriteSaveBuf(buf, OverrideHospitalLevel);
-	WriteSaveBuf(buf, OverridePoliceStationLevel);
-VALIDATESAVEBUF(*size);
-}
-
-
+void
+CRestart::FindClosestPoliceRestartPoint(const CVector &pos, CVector *outPos, float *outHeading)
+{
+	if (bOverrideRestart) {
+		*outPos = OverridePosition;
+		*outHeading = OverrideHeading;
+		CancelOverrideRestart();
+		return;
+	}
+
+	eLevelName curlevel = CTheZones::FindZoneForPoint(pos);
+	float fMinDist = 16000000.0f;
+	int closestPoint = NUM_RESTART_POINTS;
+
+	// find closest point on this level
+	for (int i = 0; i < NumberOfPoliceRestarts; i++) {
+		if (CTheZones::FindZoneForPoint(PoliceRestartPoints[i]) == (OverridePoliceStationLevel != LEVEL_NONE ? OverridePoliceStationLevel : curlevel)) {
+			float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
+			if (fMinDist >= dist) {
+				fMinDist = dist;
+				closestPoint = i;
+			}
+		}
+	}
+
+	// if we didn't find anything, find closest point on any level
+	if (closestPoint == NUM_RESTART_POINTS) {
+		for (int i = 0; i < NumberOfPoliceRestarts; i++) {
+			float dist = (pos - PoliceRestartPoints[i]).MagnitudeSqr();
+			if (fMinDist >= dist) {
+				fMinDist = dist;
+				closestPoint = i;
+			}
+		}
+	}
+
+	// if we still didn't find anything, find closest path node
+	if (closestPoint == NUM_RESTART_POINTS) {
+		printf("Couldn't find a police restart zone near the player\n");
+		*outPos = ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, PATH_PED, 999999.9f)].pos;
+		*outHeading = 0.0f;
+	} else {
+		*outPos = PoliceRestartPoints[closestPoint];
+		*outHeading = PoliceRestartHeadings[closestPoint];
+	}
+}
+
+void
+CRestart::LoadAllRestartPoints(uint8 *buf, uint32 size)
+{
+	Initialise();
+
+INITSAVEBUF
+	CheckSaveHeader(buf, 'R','S','T','\0', size - SAVE_HEADER_SIZE);
+
+	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+		HospitalRestartPoints[i] = ReadSaveBuf<CVector>(buf);
+		HospitalRestartHeadings[i] = ReadSaveBuf<float>(buf);
+	}
+
+	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+		PoliceRestartPoints[i] = ReadSaveBuf<CVector>(buf);
+		PoliceRestartHeadings[i] = ReadSaveBuf<float>(buf);
+	}
+
+	NumberOfHospitalRestarts = ReadSaveBuf<uint16>(buf);
+	NumberOfPoliceRestarts = ReadSaveBuf<uint16>(buf);
+	bOverrideRestart = ReadSaveBuf<bool>(buf);
+
+	// skip something unused
+	ReadSaveBuf<uint8>(buf);
+	ReadSaveBuf<uint16>(buf);
+
+	OverridePosition = ReadSaveBuf<CVector>(buf);
+	OverrideHeading = ReadSaveBuf<float>(buf);
+	bFadeInAfterNextDeath = ReadSaveBuf<bool>(buf);
+	bFadeInAfterNextArrest = ReadSaveBuf<bool>(buf);
+	OverrideHospitalLevel = ReadSaveBuf<uint8>(buf);
+	OverridePoliceStationLevel = ReadSaveBuf<uint8>(buf);
+VALIDATESAVEBUF(size);
+}
+
+void
+CRestart::SaveAllRestartPoints(uint8 *buf, uint32 *size)
+{
+	*size = SAVE_HEADER_SIZE
+		+ sizeof(HospitalRestartPoints)
+		+ sizeof(HospitalRestartHeadings)
+		+ sizeof(PoliceRestartPoints)
+		+ sizeof(PoliceRestartHeadings)
+		+ sizeof(NumberOfHospitalRestarts)
+		+ sizeof(NumberOfPoliceRestarts)
+		+ sizeof(bOverrideRestart)
+		+ sizeof(uint8)
+		+ sizeof(uint16)
+		+ sizeof(OverridePosition)
+		+ sizeof(OverrideHeading)
+		+ sizeof(bFadeInAfterNextDeath)
+		+ sizeof(bFadeInAfterNextArrest)
+		+ sizeof(OverrideHospitalLevel)
+		+ sizeof(OverridePoliceStationLevel); // == 292
+
+INITSAVEBUF
+	WriteSaveHeader(buf, 'R','S','T','\0', *size - SAVE_HEADER_SIZE);
+
+	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+		WriteSaveBuf(buf, HospitalRestartPoints[i]);
+		WriteSaveBuf(buf, HospitalRestartHeadings[i]);
+	}
+
+	for (int i = 0; i < NUM_RESTART_POINTS; i++) {
+		WriteSaveBuf(buf, PoliceRestartPoints[i]);
+		WriteSaveBuf(buf, PoliceRestartHeadings[i]);
+	}
+
+	WriteSaveBuf(buf, NumberOfHospitalRestarts);
+	WriteSaveBuf(buf, NumberOfPoliceRestarts);
+	WriteSaveBuf(buf, bOverrideRestart);
+
+	WriteSaveBuf(buf, (uint8)0);
+	WriteSaveBuf(buf, (uint16)0);
+
+	WriteSaveBuf(buf, OverridePosition);
+	WriteSaveBuf(buf, OverrideHeading);
+	WriteSaveBuf(buf, bFadeInAfterNextDeath);
+	WriteSaveBuf(buf, bFadeInAfterNextArrest);
+	WriteSaveBuf(buf, OverrideHospitalLevel);
+	WriteSaveBuf(buf, OverridePoliceStationLevel);
+VALIDATESAVEBUF(*size);
+}
+
+
 STARTPATCHES
 	InjectHook(0x435E20, &CRestart::Initialise, PATCH_JUMP);
 	InjectHook(0x436100, &CRestart::AddHospitalRestartPoint, PATCH_JUMP);
@@ -258,5 +258,5 @@ STARTPATCHES
 	InjectHook(0x4361A0, &CRestart::FindClosestHospitalRestartPoint, PATCH_JUMP);
 	InjectHook(0x436450, &CRestart::FindClosestPoliceRestartPoint, PATCH_JUMP);
 	InjectHook(0x436B20, &CRestart::LoadAllRestartPoints, PATCH_JUMP);
-	InjectHook(0x436700, &CRestart::SaveAllRestartPoints, PATCH_JUMP);
+	InjectHook(0x436700, &CRestart::SaveAllRestartPoints, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
index e39fe481..9548bc0a 100644
--- a/src/control/RoadBlocks.cpp
+++ b/src/control/RoadBlocks.cpp
@@ -2,36 +2,202 @@
 #include "patcher.h"
 #include "RoadBlocks.h"
 #include "PathFind.h"
+#include "ModelIndices.h"
+#include "Streaming.h"
+#include "World.h"
+#include "PedPlacement.h"
+#include "Automobile.h"
+#include "CopPed.h"
+#include "VisibilityPlugins.h"
+#include "PlayerPed.h"
+#include "Wanted.h"
+#include "Camera.h"
+#include "CarCtrl.h"
+#include "General.h"
 
 int16 &CRoadBlocks::NumRoadBlocks = *(int16*)0x95CC34;
 int16 (&CRoadBlocks::RoadBlockObjects)[NUMROADBLOCKS] = *(int16(*)[NUMROADBLOCKS]) * (uintptr*)0x72B3A8;
 bool (&CRoadBlocks::InOrOut)[NUMROADBLOCKS] = *(bool(*)[NUMROADBLOCKS]) * (uintptr*)0x733810;
 
-WRAPPER void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); }
-WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); }
-
 void
 CRoadBlocks::Init(void)
 {
-    NumRoadBlocks = 0;
-    for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) {
-        if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) {
-            if (NumRoadBlocks < 600) {
-                InOrOut[NumRoadBlocks] = true;
-                RoadBlockObjects[NumRoadBlocks] = objId;
-                NumRoadBlocks++;
-            } else {
+	NumRoadBlocks = 0;
+	for (int objId = 0; objId < ThePaths.m_numMapObjects; objId++) {
+		if (ThePaths.m_objectFlags[objId] & UseInRoadBlock) {
+			if (NumRoadBlocks < NUMROADBLOCKS) {
+				InOrOut[NumRoadBlocks] = true;
+				RoadBlockObjects[NumRoadBlocks] = objId;
+				NumRoadBlocks++;
+			} else {
 #ifndef MASTER
-                printf("Not enough room for the potential roadblocks\n");
+				printf("Not enough room for the potential roadblocks\n");
 #endif
-                // FIX: Don't iterate loop after NUMROADBLOCKS
-                return;
-            }
-        }
-    }
+				// FIX: Don't iterate loop after NUMROADBLOCKS
+				return;
+			}
+		}
+	}
 
 }
 
+void
+CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode)
+{
+	static const CVector vecRoadBlockOffets[6] = { {-1.5, 1.8f, 0.0f}, {-1.5f, -1.8f, 0.0f}, {1.5f, 1.8f, 0.0f},
+	{1.5f, -1.8f, 0.0f}, {-1.5f, 0.0f, 0.0f}, {1.5, 0.0, 0.0} };
+	CEntity* pEntityToAttack = (CEntity*)FindPlayerVehicle();
+	if (!pEntityToAttack)
+		pEntityToAttack = (CEntity*)FindPlayerPed();
+	CColModel* pPoliceColModel = CModelInfo::GetModelInfo(MI_POLICE)->GetColModel();
+	float fRadius = pVehicle->GetBoundRadius() / pPoliceColModel->boundingSphere.radius;
+	for (int32 i = 0; i < 2; i++) {
+		const int32 roadBlockIndex = i + 2 * roadBlockType;
+		CVector posForZ = pVehicle->m_matrix * (fRadius * vecRoadBlockOffets[roadBlockIndex]);
+		int32 modelInfoId = MI_COP;
+		eCopType copType = COP_STREET;
+		switch (pVehicle->GetModelIndex())
+		{
+		case MI_FBICAR:
+			modelInfoId = MI_FBI;
+			copType = COP_FBI;
+			break;
+		case MI_ENFORCER:
+			modelInfoId = MI_SWAT;
+			copType = COP_SWAT;
+			break;
+		case MI_BARRACKS:
+			modelInfoId = MI_ARMY;
+			copType = COP_ARMY;
+			break;
+		}
+		if (!CStreaming::HasModelLoaded(modelInfoId))
+			copType = COP_STREET;
+		CCopPed* pCopPed = new CCopPed(copType);
+		if (copType == COP_STREET)
+			pCopPed->SetCurrentWeapon(WEAPONTYPE_COLT45);
+		CPedPlacement::FindZCoorForPed(&posForZ);
+		pCopPed->m_matrix.GetPosition() = posForZ;
+		CVector vecSavedPos = pCopPed->m_matrix.GetPosition();
+		pCopPed->m_matrix.SetRotate(0.0f, 0.0f, -HALFPI);
+		pCopPed->m_matrix.GetPosition() += vecSavedPos;
+		pCopPed->m_bIsDisabledCop = true;
+		pCopPed->SetIdle();
+		pCopPed->bKindaStayInSamePlace = true;
+		pCopPed->bNotAllowedToDuck = false;
+		pCopPed->m_wRoadblockNode = roadBlockNode;
+		pCopPed->bCrouchWhenShooting = roadBlockType != 2;
+		if (pEntityToAttack) {
+			pCopPed->m_pPointGunAt = pEntityToAttack;
+			pEntityToAttack->RegisterReference(&pCopPed->m_pPointGunAt);
+			pCopPed->SetAttack(pEntityToAttack);
+		}
+		pCopPed->m_pMyVehicle = pVehicle;
+		pVehicle->RegisterReference((CEntity**)&pCopPed->m_pMyVehicle);
+		pCopPed->bCullExtraFarAway = true;
+		CVisibilityPlugins::SetClumpAlpha(pCopPed->GetClump(), 0);
+		CWorld::Add(pCopPed);
+	}
+}
+
+void 
+CRoadBlocks::GenerateRoadBlocks(void) 
+{ 
+	CMatrix offsetMatrix;
+	uint32 frame = CTimer::GetFrameCounter() & 0xF;
+	int16 nRoadblockNode = (int16)(NUMROADBLOCKS * frame) / 16;
+	const int16 maxRoadBlocks = (int16)(NUMROADBLOCKS * (frame + 1)) / 16;
+	int16 numRoadBlocks = CRoadBlocks::NumRoadBlocks;
+	if (CRoadBlocks::NumRoadBlocks >= maxRoadBlocks)
+		numRoadBlocks = maxRoadBlocks;
+	for (; nRoadblockNode < numRoadBlocks; nRoadblockNode++) {
+		CTreadable *mapObject = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[nRoadblockNode]];
+		CVector2D vecDistance = FindPlayerCoors() - mapObject->GetPosition();
+		if (vecDistance.x > -80.0f && vecDistance.x < 80.0f &&
+			vecDistance.y > -80.0f && vecDistance.y < 80.0f &&
+			vecDistance.Magnitude() < 80.0f) {
+			if (!CRoadBlocks::InOrOut[nRoadblockNode]) {
+				CRoadBlocks::InOrOut[nRoadblockNode] = true;
+				if (FindPlayerVehicle() && (CGeneral::GetRandomNumber() & 0x7F) < FindPlayerPed()->m_pWanted->m_RoadblockDensity) {
+					CWanted *pPlayerWanted = FindPlayerPed()->m_pWanted;
+					float fMapObjectRadius = 2.0f * mapObject->GetColModel()->boundingBox.max.x;
+					int32 vehicleId = MI_POLICE;
+					if (pPlayerWanted->AreArmyRequired())
+						vehicleId = MI_BARRACKS;
+					else if (pPlayerWanted->AreFbiRequired())
+						vehicleId = MI_FBICAR;
+					else if (pPlayerWanted->AreSwatRequired())
+						vehicleId = MI_ENFORCER;
+					if (!CStreaming::HasModelLoaded(vehicleId))
+						vehicleId = MI_POLICE;
+					CColModel *pVehicleColModel = CModelInfo::GetModelInfo(vehicleId)->GetColModel();
+					float fModelRadius = 2.0f * pVehicleColModel->boundingSphere.radius + 0.25f;
+					int16 radius = (int16)(fMapObjectRadius / fModelRadius);
+					if (radius > 0 && radius < 6) {
+						CVector2D vecDistanceToCamera = TheCamera.GetPosition() - mapObject->m_matrix.GetPosition();
+						float fDotProduct = DotProduct2D(vecDistanceToCamera, mapObject->m_matrix.GetUp());
+						float fOffset = 0.5f * fModelRadius * (float)(radius - 1);
+						for (int16 i = 0; i < radius; i++) {
+							uint8 nRoadblockType = fDotProduct < 0.0f;
+							if (CGeneral::GetRandomNumber() & 1) {
+								offsetMatrix.SetRotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f + HALFPI);
+							}
+							else {
+								nRoadblockType = !nRoadblockType;
+								offsetMatrix.SetRotateZ(((CGeneral::GetRandomNumber() & 0xFF) - 128.0f) * 0.003f - HALFPI);
+							}
+							if (ThePaths.m_objectFlags[CRoadBlocks::RoadBlockObjects[nRoadblockNode]] & ObjectEastWest)
+								offsetMatrix.GetPosition() = CVector(0.0f, -fOffset, 0.6f);
+							else
+								offsetMatrix.GetPosition() = CVector(-fOffset, 0.0f, 0.6f);
+							CMatrix vehicleMatrix = mapObject->m_matrix * offsetMatrix;
+							float fModelRadius = CModelInfo::GetModelInfo(vehicleId)->GetColModel()->boundingSphere.radius - 0.25f;
+							int16 colliding = 0;
+							CWorld::FindObjectsKindaColliding(vehicleMatrix.GetPosition(), fModelRadius, 0, &colliding, 2, nil, false, true, true, false, false);
+							if (!colliding) {
+								CAutomobile *pVehicle = new CAutomobile(vehicleId, RANDOM_VEHICLE);
+								pVehicle->m_status = STATUS_ABANDONED;
+								// pVehicle->GetHeightAboveRoad(); // called but return value is ignored?
+								vehicleMatrix.GetPosition().z += fModelRadius - 0.6f;
+								pVehicle->m_matrix = vehicleMatrix;
+								pVehicle->PlaceOnRoadProperly();
+								pVehicle->bIsStatic = false;
+								pVehicle->m_matrix.UpdateRW();
+								pVehicle->m_nDoorLock = CARLOCK_UNLOCKED;
+								CCarCtrl::JoinCarWithRoadSystem(pVehicle);
+								pVehicle->bIsLocked = false;
+								pVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
+								pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+								pVehicle->AutoPilot.m_nCurrentLane = 0;
+								pVehicle->AutoPilot.m_nNextLane = 0;
+								pVehicle->AutoPilot.m_fMaxTrafficSpeed = 0.0f;
+								pVehicle->AutoPilot.m_nCruiseSpeed = 0.0f;
+								pVehicle->bExtendedRange = true;
+								if (pVehicle->UsesSiren(pVehicle->GetModelIndex()) && CGeneral::GetRandomNumber() & 1)
+									pVehicle->m_bSirenOrAlarm = true;
+								if (pVehicle->m_matrix.GetForward().z > 0.94f) {
+									CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0);
+									CWorld::Add(pVehicle);
+									pVehicle->bCreateRoadBlockPeds = true;
+									pVehicle->m_nRoadblockType = nRoadblockType;
+									pVehicle->m_nRoadblockNode = nRoadblockNode;
+								}
+								else {
+									delete pVehicle;
+								}
+							}
+						}
+					}
+				}
+			}
+		} else {
+			CRoadBlocks::InOrOut[nRoadblockNode] = false;
+		}
+	}
+}
+
 STARTPATCHES
 	InjectHook(0x436F50, &CRoadBlocks::Init, PATCH_JUMP);
+	InjectHook(0x4376A0, &CRoadBlocks::GenerateRoadBlockCopsForCar, PATCH_JUMP);
+	InjectHook(0x436FA0, &CRoadBlocks::GenerateRoadBlocks, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h
index 3f5868e7..16e3a362 100644
--- a/src/control/RoadBlocks.h
+++ b/src/control/RoadBlocks.h
@@ -11,6 +11,6 @@ public:
 	static bool (&InOrOut)[NUMROADBLOCKS];
 
 	static void Init(void);
-	static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16);
+	static void GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode);
 	static void GenerateRoadBlocks(void);
 };
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index f96ec060..ff89f0fc 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -91,10 +91,10 @@ uint8 (&CTheScripts::ScriptSpace)[SIZE_SCRIPT_SPACE] = *(uint8(*)[SIZE_SCRIPT_SP
 CRunningScript(&CTheScripts::ScriptsArray)[MAX_NUM_SCRIPTS] = *(CRunningScript(*)[MAX_NUM_SCRIPTS])*(uintptr*)0x6F5C08;
 int32(&CTheScripts::BaseBriefIdForContact)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x880200;
 int32(&CTheScripts::OnAMissionForContactFlag)[MAX_NUM_CONTACTS] = *(int32(*)[MAX_NUM_CONTACTS])*(uintptr*)0x8622F0;
-CTextLine (&CTheScripts::IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES] = *(CTextLine (*)[MAX_NUM_INTRO_TEXT_LINES])*(uintptr*)0x70EA68;
-CScriptRectangle (&CTheScripts::IntroRectangles)[MAX_NUM_INTRO_RECTANGLES] = *(CScriptRectangle (*)[MAX_NUM_INTRO_RECTANGLES])*(uintptr*)0x72D108;
+intro_text_line (&CTheScripts::IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES] = *(intro_text_line (*)[MAX_NUM_INTRO_TEXT_LINES])*(uintptr*)0x70EA68;
+intro_script_rectangle (&CTheScripts::IntroRectangles)[MAX_NUM_INTRO_RECTANGLES] = *(intro_script_rectangle (*)[MAX_NUM_INTRO_RECTANGLES])*(uintptr*)0x72D108;
 CSprite2d (&CTheScripts::ScriptSprites)[MAX_NUM_SCRIPT_SRPITES] = *(CSprite2d(*)[MAX_NUM_SCRIPT_SRPITES])*(uintptr*)0x72B090;
-CScriptSphere(&CTheScripts::ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES] = *(CScriptSphere(*)[MAX_NUM_SCRIPT_SPHERES])*(uintptr*)0x727D60;
+script_sphere_struct(&CTheScripts::ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES] = *(script_sphere_struct(*)[MAX_NUM_SCRIPT_SPHERES])*(uintptr*)0x727D60;
 tCollectiveData(&CTheScripts::CollectiveArray)[MAX_NUM_COLLECTIVES] = *(tCollectiveData(*)[MAX_NUM_COLLECTIVES])*(uintptr*)0x6FA008;
 tUsedObject(&CTheScripts::UsedObjectArray)[MAX_NUM_USED_OBJECTS] = *(tUsedObject(*)[MAX_NUM_USED_OBJECTS])*(uintptr*)0x6E69C8;
 int32(&CTheScripts::MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS] = *(int32(*)[MAX_NUM_MISSION_SCRIPTS])*(uintptr*)0x6F0558;
@@ -313,7 +313,7 @@ bool CUpsideDownCarCheck::HasCarBeenUpsideDownForAWhile(int32 id)
 	return false;
 }
 
-void CStuckCarCheckEntry::Reset()
+void stuck_car_data::Reset()
 {
 	m_nVehicleIndex = -1;
 	m_vecPos = CVector(-5000.0f, -5000.0f, -5000.0f);
@@ -2229,6 +2229,7 @@ int8 CRunningScript::ProcessCommands100To199(int32 command)
 		if (pos.z <= -100)
 			pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
 		UpdateCompareFlag(TheCamera.IsSphereVisible(pos, *(float*)&ScriptParams[3]));
+		return 0;
 	}
 	case COMMAND_DEBUG_ON:
 		CTheScripts::DbgFlag = true;
@@ -7116,7 +7117,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command)
 	case COMMAND_CLOSE_GARAGE:
 	{
 		CollectParameters(&m_nIp, 1);
-		CGarages::CloseGarage(ScriptParams[1]);
+		CGarages::CloseGarage(ScriptParams[0]);
 		return 0;
 	}
 	case COMMAND_WARP_CHAR_FROM_CAR_TO_COORD:
@@ -7657,13 +7658,13 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
 		assert(pObject);
 		if (ScriptParams[1]) {
 			if (pObject->bIsStatic) {
-				pObject->bIsStatic = true;
+				pObject->bIsStatic = false;
 				pObject->AddToMovingList();
 			}
 		}
 		else {
 			if (!pObject->bIsStatic) {
-				pObject->bIsStatic = false;
+				pObject->bIsStatic = true;
 				pObject->RemoveFromMovingList();
 			}
 		}
@@ -8441,7 +8442,7 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command)
 		CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]];
 		CPad::GetPad(ScriptParams[0])->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80;
 		pPlayerInfo->MakePlayerSafe(true);
-		CCutsceneMgr::SetRunning(true);
+		CCutsceneMgr::StartCutsceneProcessing();
 		return 0;
 	}
 	case COMMAND_USE_TEXT_COMMANDS:
@@ -9140,7 +9141,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command)
 		assert(pVehicle);
 		assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR);
 		CAutomobile* pCar = (CAutomobile*)pVehicle;
-		pCar->bTakeLessDamage = ScriptParams[1];
+		pCar->bMoreResistantToDamage = ScriptParams[1];
 		return 0;
 	}
 	case COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER:
@@ -9152,6 +9153,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command)
 		return 0;
 	}
 	case COMMAND_LOAD_END_OF_GAME_TUNE:
+		DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
 		printf("Start preload end of game audio\n");
 		DMAudio.PreloadCutSceneMusic(STREAMED_SOUND_GAME_COMPLETED);
 		printf("End preload end of game audio\n");
@@ -11037,6 +11039,7 @@ void CRunningScript::DoDeatharrestCheck()
 		int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact];
 		if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) {
 			messageId += CTheScripts::BaseBriefIdForContact[contact];
+			found = true;
 		}
 	}
 	if (!found)
@@ -11331,6 +11334,7 @@ INITSAVEBUF
 			break;
 		case 4:
 			InvisibilitySettingArray[i] = CPools::GetDummyPool()->GetSlot(handle - 1);
+			break;
 		default:
 			assert(false);
 		}
@@ -11369,15 +11373,15 @@ void CTheScripts::ClearSpaceForMissionEntity(const CVector& pos, CEntity* pEntit
 			continue;
 		CEntity* pFound = aEntities[i];
 		int cols;
-		if (CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel()->numLines <= 0)
-			cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(),
-				pFound->GetMatrix(), *CModelInfo::GetModelInfo(pFound->GetModelIndex())->GetColModel(), aTempColPoints, nil, nil);
+		if (pEntity->GetColModel()->numLines <= 0)
+			cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(),
+				pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints, nil, nil);
 		else {
 			float lines[4];
 			lines[0] = lines[1] = lines[2] = lines[3] = 1.0f;
-			CColPoint tmp;
-			cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *CModelInfo::GetModelInfo(pEntity->GetModelIndex())->GetColModel(),
-				pFound->GetMatrix(), *CModelInfo::GetModelInfo(pFound->GetModelIndex())->GetColModel(), aTempColPoints, &tmp, lines);
+			CColPoint tmp[4];
+			cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(),
+				pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints,tmp, lines);
 		}
 		if (cols <= 0)
 			continue;
diff --git a/src/control/Script.h b/src/control/Script.h
index fbcdce48..4338bd18 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -15,22 +15,25 @@ class CRunningScript;
 
 #define KEY_LENGTH_IN_SCRIPT 8
 
-struct CScriptRectangle 
+struct intro_script_rectangle 
 {
-	int8 m_bIsUsed;
+	bool m_bIsUsed;
 	bool m_bBeforeFade;
 	int16 m_nTextureId;
 	CRect m_sRect;
 	CRGBA m_sColor;
+	
+	intro_script_rectangle() { }
+	~intro_script_rectangle() { }
 };
 
-static_assert(sizeof(CScriptRectangle) == 0x18, "Script.h: error");
+static_assert(sizeof(intro_script_rectangle) == 0x18, "Script.h: error");
 
 enum {
 	SCRIPT_TEXT_MAX_LENGTH = 500
 };
 
-struct CTextLine 
+struct intro_text_line 
 {
 	float m_fScaleX;
 	float m_fScaleY;
@@ -50,6 +53,9 @@ struct CTextLine
 	float m_fAtY;
 	wchar m_Text[SCRIPT_TEXT_MAX_LENGTH];
 
+	intro_text_line() { }
+	~intro_text_line() { }
+	
 	void Reset()
 	{
 		m_fScaleX = 0.48f;
@@ -72,15 +78,17 @@ struct CTextLine
 	}
 };
 
-static_assert(sizeof(CTextLine) == 0x414, "Script.h: error");
+static_assert(sizeof(intro_text_line) == 0x414, "Script.h: error");
 
-struct CScriptSphere
+struct script_sphere_struct
 {
 	bool m_bInUse;
 	uint16 m_Index;
 	uint32 m_Id;
 	CVector m_vecCenter;
 	float m_fRadius;
+	
+	script_sphere_struct() { }
 };
 
 struct CStoredLine
@@ -145,7 +153,7 @@ public:
 	bool HasCarBeenUpsideDownForAWhile(int32);
 };
 
-struct CStuckCarCheckEntry
+struct stuck_car_data
 {
 	int32 m_nVehicleIndex;
 	CVector m_vecPos;
@@ -154,12 +162,13 @@ struct CStuckCarCheckEntry
 	uint32 m_nStuckTime;
 	bool m_bStuck;
 
+	stuck_car_data() { }
 	inline void Reset();
 };
 
 class CStuckCarCheck
 {
-	CStuckCarCheckEntry m_sCars[MAX_STUCK_CAR_CHECKS];
+	stuck_car_data m_sCars[MAX_STUCK_CAR_CHECKS];
 
 public:
 	void Init();
@@ -235,10 +244,10 @@ class CTheScripts
 	static CRunningScript(&ScriptsArray)[MAX_NUM_SCRIPTS];
 	static int32(&BaseBriefIdForContact)[MAX_NUM_CONTACTS];
 	static int32(&OnAMissionForContactFlag)[MAX_NUM_CONTACTS];
-	static CTextLine(&IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES];
-	static CScriptRectangle(&IntroRectangles)[MAX_NUM_INTRO_RECTANGLES];
+	static intro_text_line(&IntroTextLines)[MAX_NUM_INTRO_TEXT_LINES];
+	static intro_script_rectangle(&IntroRectangles)[MAX_NUM_INTRO_RECTANGLES];
 	static CSprite2d(&ScriptSprites)[MAX_NUM_SCRIPT_SRPITES];
-	static CScriptSphere(&ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES];
+	static script_sphere_struct(&ScriptSphereArray)[MAX_NUM_SCRIPT_SPHERES];
 	static tCollectiveData(&CollectiveArray)[MAX_NUM_COLLECTIVES];
 	static tUsedObject(&UsedObjectArray)[MAX_NUM_USED_OBJECTS];
 	static int32(&MultiScriptArray)[MAX_NUM_MISSION_SCRIPTS];
diff --git a/src/control/TrafficLights.cpp b/src/control/TrafficLights.cpp
index 2cd09a03..ab9cd92d 100644
--- a/src/control/TrafficLights.cpp
+++ b/src/control/TrafficLights.cpp
@@ -1,23 +1,335 @@
 #include "common.h"
 #include "patcher.h"
-#include "TrafficLights.h"
+#include "General.h"
+#include "Camera.h"
+#include "World.h"
+#include "PathFind.h"
 #include "Timer.h"
+#include "Clock.h"
+#include "Weather.h"
+#include "Timecycle.h"
+#include "Pointlights.h"
+#include "Shadows.h"
+#include "Coronas.h"
+#include "SpecialFX.h"
 #include "Vehicle.h"
+#include "TrafficLights.h"
 
-WRAPPER void CTrafficLights::DisplayActualLight(CEntity *ent) { EAXJMP(0x455800); }
-WRAPPER void CTrafficLights::ScanForLightsOnMap(void) { EAXJMP(0x454F40); }
-WRAPPER bool CTrafficLights::ShouldCarStopForLight(CVehicle*, bool) { EAXJMP(0x455350); }
-WRAPPER bool CTrafficLights::ShouldCarStopForBridge(CVehicle*) { EAXJMP(0x456460); }
+// TODO: figure out the meaning of this
+enum { SOME_FLAG = 0x80 };
+
+void
+CTrafficLights::DisplayActualLight(CEntity *ent)
+{
+	if(ent->GetUp().z < 0.96f || ent->bRenderDamaged)
+		return;
+
+	int phase;
+	if(FindTrafficLightType(ent) == 1)
+		phase = LightForCars1();
+	else
+		phase = LightForCars2();
+
+	int i;
+	CBaseModelInfo *mi = CModelInfo::GetModelInfo(ent->GetModelIndex());
+	float x = mi->Get2dEffect(0)->pos.x;
+	float yMin = mi->Get2dEffect(0)->pos.y;
+	float yMax = mi->Get2dEffect(0)->pos.y;
+	float zMin = mi->Get2dEffect(0)->pos.z;
+	float zMax = mi->Get2dEffect(0)->pos.z;
+	for(i = 1; i < 6; i++){
+		assert(mi->Get2dEffect(i));
+		yMin = min(yMin, mi->Get2dEffect(i)->pos.y);
+		yMax = max(yMax, mi->Get2dEffect(i)->pos.y);
+		zMin = min(zMin, mi->Get2dEffect(i)->pos.z);
+		zMax = max(zMax, mi->Get2dEffect(i)->pos.z);
+	}
+
+	CVector pos1, pos2;
+	uint8 r, g;
+	int id;
+	switch(phase){
+	case CAR_LIGHTS_GREEN:
+		r = 0;
+		g = 255;
+		pos1 = ent->GetMatrix() * CVector(x, yMax, zMin);
+		pos2 = ent->GetMatrix() * CVector(x, yMin, zMin);
+		id = 0;
+		break;
+	case CAR_LIGHTS_YELLOW:
+		r = 255;
+		g = 128;
+		pos1 = ent->GetMatrix() * CVector(x, yMax, (zMin+zMax)/2.0f);
+		pos2 = ent->GetMatrix() * CVector(x, yMin, (zMin+zMax)/2.0f);
+		id = 1;
+		break;
+	case CAR_LIGHTS_RED:
+	default:
+		r = 255;
+		g = 0;
+		pos1 = ent->GetMatrix() * CVector(x, yMax, zMax);
+		pos2 = ent->GetMatrix() * CVector(x, yMin, zMax);
+		id = 2;
+		break;
+	}
+
+	if(CClock::GetHours() > 19 || CClock::GetHours() < 6 || CWeather::Foggyness > 0.05f)
+		CPointLights::AddLight(CPointLights::LIGHT_POINT,
+			pos1, CVector(0.0f, 0.0f, 0.0f), 8.0f,
+			r/255.0f, g/255.0f, 0/255.0f, CPointLights::FOG_NORMAL, true);
+
+	CShadows::StoreStaticShadow((uintptr)ent,
+		SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &pos1,
+		8.0f, 0.0f, 0.0f, -8.0f, 128,
+		r*CTimeCycle::GetLightOnGroundBrightness()/8.0f,
+		g*CTimeCycle::GetLightOnGroundBrightness()/8.0f,
+		0*CTimeCycle::GetLightOnGroundBrightness()/8.0f,
+		12.0f, 1.0f, 40.0f, false, 0.0f);
+
+	if(DotProduct(TheCamera.GetForward(), ent->GetForward()) < 0.0f)
+		CCoronas::RegisterCorona((uintptr)ent + id,
+			r*CTimeCycle::GetSpriteBrightness()*0.7f,
+			g*CTimeCycle::GetSpriteBrightness()*0.7f,
+			0*CTimeCycle::GetSpriteBrightness()*0.7f,
+			255,
+			pos1, 1.75f*CTimeCycle::GetSpriteSize(), 50.0f,
+			CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+			CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+	else
+		CCoronas::RegisterCorona((uintptr)ent + id + 3,
+			r*CTimeCycle::GetSpriteBrightness()*0.7f,
+			g*CTimeCycle::GetSpriteBrightness()*0.7f,
+			0*CTimeCycle::GetSpriteBrightness()*0.7f,
+			255,
+			pos2, 1.75f*CTimeCycle::GetSpriteSize(), 50.0f,
+			CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+			CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+
+	CBrightLights::RegisterOne(pos1, ent->GetUp(), ent->GetRight(), CVector(0.0f, 0.0f, 0.0f), id + BRIGHTLIGHT_TRAFFIC_GREEN);
+	CBrightLights::RegisterOne(pos2, ent->GetUp(), -ent->GetRight(), CVector(0.0f, 0.0f, 0.0f), id + BRIGHTLIGHT_TRAFFIC_GREEN);
+
+	static const float top = -0.127f;
+	static const float bot = -0.539f;
+	static const float mid = bot + (top-bot)/3.0f;
+	static const float left = 1.256f;
+	static const float right = 0.706f;
+	phase = CTrafficLights::LightForPeds();
+	if(phase == PED_LIGHTS_DONT_WALK){
+		CVector p0(2.7f, right, top);
+		CVector p1(2.7f, left, top);
+		CVector p2(2.7f, right, mid);
+		CVector p3(2.7f, left, mid);
+		CShinyTexts::RegisterOne(ent->GetMatrix()*p0, ent->GetMatrix()*p1, ent->GetMatrix()*p2, ent->GetMatrix()*p3,
+			1.0f, 0.0f,  0.0f, 0.0f,  1.0f, 1.0f,  0.0f, 1.0f,
+			SHINYTEXT_WALK, 255, 0, 0, 60.0f);
+	}else if(phase == PED_LIGHTS_WALK || CTimer::GetTimeInMilliseconds() & 0x100){
+		CVector p0(2.7f, right, mid);
+		CVector p1(2.7f, left, mid);
+		CVector p2(2.7f, right, bot);
+		CVector p3(2.7f, left, bot);
+		CShinyTexts::RegisterOne(ent->GetMatrix()*p0, ent->GetMatrix()*p1, ent->GetMatrix()*p2, ent->GetMatrix()*p3,
+			1.0f, 0.5f,  0.0f, 0.5f,  1.0f, 1.0f,  0.0f, 1.0f,
+			SHINYTEXT_WALK, 255, 255, 255, 60.0f);
+	}
+}
+
+void
+CTrafficLights::ScanForLightsOnMap(void)
+{
+	int x, y;
+	int i, j, l;
+	CPtrNode *node;
+
+	for(x = 0; x < NUMSECTORS_X; x++)
+	for(y = 0; y < NUMSECTORS_Y; y++){
+		CPtrList &list = CWorld::GetSector(x, y)->m_lists[ENTITYLIST_DUMMIES];
+		for(node = list.first; node; node = node->next){
+			CEntity *light = (CEntity*)node->item;
+			if(light->GetModelIndex() != MI_TRAFFICLIGHTS)
+				continue;
+
+			// Check cars
+			for(i = 0; i < ThePaths.m_numCarPathLinks; i++){
+				CVector2D dist = ThePaths.m_carPathLinks[i].pos - light->GetPosition();
+				float dotY = Abs(DotProduct2D(dist, light->GetForward()));	// forward is direction of car light
+				float dotX = DotProduct2D(dist, light->GetRight());	// towards base of light
+				// it has to be on the correct side of the node and also not very far away
+				if(dotX < 0.0f && dotX > -15.0f && dotY < 3.0f){
+					float dz = ThePaths.m_pathNodes[ThePaths.m_carPathLinks[i].pathNodeIndex].pos.z -
+						light->GetPosition().z;
+					if(dz < 15.0f){
+						ThePaths.m_carPathLinks[i].trafficLightType = FindTrafficLightType(light);
+						// Find two neighbour nodes of this one
+						int n1 = -1;
+						int n2 = -1;
+						for(j = 0; j < ThePaths.m_numPathNodes; j++)
+							for(l = 0; l < ThePaths.m_pathNodes[j].numLinks; l++)
+								if(ThePaths.m_carPathConnections[ThePaths.m_pathNodes[j].firstLink + l] == i){
+									if(n1 == -1)
+										n1 = j;
+									else
+										n2 = j;
+								}
+						// What's going on here?
+						if(ThePaths.m_pathNodes[n1].numLinks <= ThePaths.m_pathNodes[n2].numLinks)
+							n1 = n2;
+						if(ThePaths.m_carPathLinks[i].pathNodeIndex != n1)
+							ThePaths.m_carPathLinks[i].trafficLightType |= SOME_FLAG;
+					}
+				}
+			}
+
+			// Check peds
+			for(i = ThePaths.m_numCarPathNodes; i < ThePaths.m_numPathNodes; i++){
+				float dist1, dist2;
+				dist1 = Abs(ThePaths.m_pathNodes[i].pos.x - light->GetPosition().x) +
+					Abs(ThePaths.m_pathNodes[i].pos.y - light->GetPosition().y);
+				if(dist1 < 50.0f){
+					for(l = 0; l < ThePaths.m_pathNodes[i].numLinks; l++){
+						j = ThePaths.m_pathNodes[i].firstLink + l;
+						if(ThePaths.m_connectionFlags[j].bCrossesRoad){
+							dist2 = Abs(ThePaths.m_pathNodes[j].pos.x - light->GetPosition().x) +
+								Abs(ThePaths.m_pathNodes[j].pos.y - light->GetPosition().y);
+							if(dist1 < 15.0f || dist2 < 15.0f)
+								ThePaths.m_connectionFlags[j].bTrafficLight = true;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+bool
+CTrafficLights::ShouldCarStopForLight(CVehicle *vehicle, bool alwaysStop)
+{
+	int node, type;
+
+	node = vehicle->AutoPilot.m_nNextPathNodeInfo;
+	type = ThePaths.m_carPathLinks[node].trafficLightType;
+	if(type){
+		if((type & SOME_FLAG || ThePaths.m_carPathLinks[node].pathNodeIndex == vehicle->AutoPilot.m_nNextRouteNode) &&
+		   (!(type & SOME_FLAG) || ThePaths.m_carPathLinks[node].pathNodeIndex != vehicle->AutoPilot.m_nNextRouteNode))
+			if(alwaysStop ||
+			   (type&~SOME_FLAG) == 1 && LightForCars1() != CAR_LIGHTS_GREEN ||
+			   (type&~SOME_FLAG) == 2 && LightForCars2() != CAR_LIGHTS_GREEN){
+				float dist = DotProduct2D(CVector2D(vehicle->GetPosition()) - ThePaths.m_carPathLinks[node].pos,
+						ThePaths.m_carPathLinks[node].dir);
+				if(vehicle->AutoPilot.m_nNextDirection == -1){
+					if(dist > 0.0f && dist < 8.0f)
+						return true;
+				}else{
+					if(dist < 0.0f && dist > -8.0f)
+						return true;
+				}
+			}
+	}
+
+	node = vehicle->AutoPilot.m_nCurrentPathNodeInfo;
+	type = ThePaths.m_carPathLinks[node].trafficLightType;
+	if(type){
+		if((type & SOME_FLAG || ThePaths.m_carPathLinks[node].pathNodeIndex == vehicle->AutoPilot.m_nCurrentRouteNode) &&
+		   (!(type & SOME_FLAG) || ThePaths.m_carPathLinks[node].pathNodeIndex != vehicle->AutoPilot.m_nCurrentRouteNode))
+			if(alwaysStop ||
+			   (type&~SOME_FLAG) == 1 && LightForCars1() != CAR_LIGHTS_GREEN ||
+			   (type&~SOME_FLAG) == 2 && LightForCars2() != CAR_LIGHTS_GREEN){
+				float dist = DotProduct2D(CVector2D(vehicle->GetPosition()) - ThePaths.m_carPathLinks[node].pos,
+						ThePaths.m_carPathLinks[node].dir);
+				if(vehicle->AutoPilot.m_nCurrentDirection == -1){
+					if(dist > 0.0f && dist < 8.0f)
+						return true;
+				}else{
+					if(dist < 0.0f && dist > -8.0f)
+						return true;
+				}
+			}
+	}
+
+	if(vehicle->m_status == STATUS_PHYSICS){
+		node = vehicle->AutoPilot.m_nPreviousPathNodeInfo;
+		type = ThePaths.m_carPathLinks[node].trafficLightType;
+		if(type){
+			if((type & SOME_FLAG || ThePaths.m_carPathLinks[node].pathNodeIndex == vehicle->AutoPilot.m_nPrevRouteNode) &&
+			   (!(type & SOME_FLAG) || ThePaths.m_carPathLinks[node].pathNodeIndex != vehicle->AutoPilot.m_nPrevRouteNode))
+				if(alwaysStop ||
+				   (type&~SOME_FLAG) == 1 && LightForCars1() != CAR_LIGHTS_GREEN ||
+				   (type&~SOME_FLAG) == 2 && LightForCars2() != CAR_LIGHTS_GREEN){
+					float dist = DotProduct2D(CVector2D(vehicle->GetPosition()) - ThePaths.m_carPathLinks[node].pos,
+							ThePaths.m_carPathLinks[node].dir);
+					if(vehicle->AutoPilot.m_nPreviousDirection == -1){
+						if(dist > 0.0f && dist < 6.0f)
+							return true;
+					}else{
+						if(dist < 0.0f && dist > -6.0f)
+							return true;
+					}
+				}
+		}
+	}
+
+	return false;
+}
+
+bool
+CTrafficLights::ShouldCarStopForBridge(CVehicle *vehicle)
+{
+	return ThePaths.m_carPathLinks[vehicle->AutoPilot.m_nNextPathNodeInfo].bBridgeLights &&
+		!ThePaths.m_carPathLinks[vehicle->AutoPilot.m_nCurrentPathNodeInfo].bBridgeLights;
+}
+
+int
+CTrafficLights::FindTrafficLightType(CEntity *light)
+{
+	float orientation = RADTODEG(CGeneral::GetATanOfXY(light->GetForward().x, light->GetForward().y));
+	if((orientation > 60.0f && orientation < 60.0f + 90.0f) ||
+	   (orientation > 240.0f && orientation < 240.0f + 90.0f))
+		return 1;
+	return 2;
+}
 
 uint8
 CTrafficLights::LightForPeds(void)
 {
-	uint32 period = CTimer::GetTimeInMilliseconds() & 0x3FFF; // Equals to % 16384
+	uint32 period = CTimer::GetTimeInMilliseconds() % 16384;
 
-	if (period >= 15384)
-		return PED_LIGHTS_WALK_BLINK;
-	else if (period >= 12000)
+	if(period < 12000)
+		return PED_LIGHTS_DONT_WALK;
+	else if(period < 16384 - 1000)
 		return PED_LIGHTS_WALK;
 	else
-		return PED_LIGHTS_DONT_WALK;
-}
\ No newline at end of file
+		return PED_LIGHTS_WALK_BLINK;
+}
+
+uint8
+CTrafficLights::LightForCars1(void)
+{
+	uint32 period = CTimer::GetTimeInMilliseconds() % 16384;
+
+	if(period < 5000)
+		return CAR_LIGHTS_GREEN;
+	else if(period < 5000 + 1000)
+		return CAR_LIGHTS_YELLOW;
+	else
+		return CAR_LIGHTS_RED;
+}
+
+uint8
+CTrafficLights::LightForCars2(void)
+{
+	uint32 period = CTimer::GetTimeInMilliseconds() % 16384;
+
+	if(period < 6000)
+		return CAR_LIGHTS_RED;
+	else if(period < 12000 - 1000)
+		return CAR_LIGHTS_GREEN;
+	else if(period < 12000)
+		return CAR_LIGHTS_YELLOW;
+	else
+		return CAR_LIGHTS_RED;
+}
+
+STARTPATCHES
+	InjectHook(0x455760, &CTrafficLights::LightForCars1, PATCH_JUMP);
+	InjectHook(0x455790, &CTrafficLights::LightForCars2, PATCH_JUMP);
+	InjectHook(0x4557D0, &CTrafficLights::LightForPeds, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/control/TrafficLights.h b/src/control/TrafficLights.h
index 06505ed6..f3df6cd5 100644
--- a/src/control/TrafficLights.h
+++ b/src/control/TrafficLights.h
@@ -7,6 +7,10 @@ enum {
 	PED_LIGHTS_WALK,
 	PED_LIGHTS_WALK_BLINK,
 	PED_LIGHTS_DONT_WALK,
+
+	CAR_LIGHTS_GREEN = 0,
+	CAR_LIGHTS_YELLOW,
+	CAR_LIGHTS_RED
 };
 
 class CTrafficLights
@@ -14,7 +18,10 @@ class CTrafficLights
 public:
 	static void DisplayActualLight(CEntity *ent);
 	static void ScanForLightsOnMap(void);
+	static int FindTrafficLightType(CEntity *light);
 	static uint8 LightForPeds(void);
+	static uint8 LightForCars1(void);
+	static uint8 LightForCars2(void);
 	static bool ShouldCarStopForLight(CVehicle*, bool);
 	static bool ShouldCarStopForBridge(CVehicle*);
 };
diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index 5b7a53e9..cfdea46a 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -3511,7 +3511,7 @@ CCam::Process_FlyBy(const CVector&, float, float, float)
 
 	Up = CVector(0.0f, 0.0f, 1.0f);
 	if(TheCamera.m_bStartingSpline)
-		m_fTimeElapsedFloat += CTimer::GetTimeStepInMilliseconds();
+		m_fTimeElapsedFloat += CTimer::GetTimeStepNonClippedInMilliseconds();
 	else{
 		m_fTimeElapsedFloat = 0.0f;
 		m_uiFinishTime = MS(TheCamera.m_arrPathArray[2].m_arr_PathData[10*((int)TheCamera.m_arrPathArray[2].m_arr_PathData[0]-1) + 1]);
@@ -4672,15 +4672,15 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 	else {
 		switch ((int)TheCamera.CarZoomIndicator) {
 			// near
-		case 1:
+		case CAM_ZOOM_1:
 			zoomModeAlphaOffset = ZmOneAlphaOffsetLCS[alphaArrPos];
 			break;
 			// mid
-		case 2:
+		case CAM_ZOOM_2:
 			zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos];
 			break;
 			// far
-		case 3:
+		case CAM_ZOOM_3:
 			zoomModeAlphaOffset = ZmThreeAlphaOffsetLCS[alphaArrPos];
 			break;
 		default:
@@ -4705,14 +4705,12 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 		}
 	} else {
 		// 0.6f = fTestShiftHeliCamTarget
-		TargetCoors.x += 0.6f * car->GetUp().x * colMaxZ;
-		TargetCoors.y += 0.6f * car->GetUp().y * colMaxZ;
-		TargetCoors.z += 0.6f * car->GetUp().z * colMaxZ;
+		TargetCoors += 0.6f * car->GetUp() * colMaxZ;
 	}
 
 	float minDistForVehType = CARCAM_SET[camSetArrPos][4];
 
-	if ((int)TheCamera.CarZoomIndicator == 1 && (camSetArrPos < 2 || camSetArrPos == 7)) {
+	if (TheCamera.CarZoomIndicator == CAM_ZOOM_1 && (camSetArrPos < 2 || camSetArrPos == 7)) {
 		minDistForVehType = minDistForVehType * 0.65f;
 	}
 
@@ -4904,8 +4902,8 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 	//		yMovement = 0.0;
 
 	if (!nextDirectionIsForward) {
-		yMovement = 0.0;
-		xMovement = 0.0;
+		yMovement = 0.0f;
+		xMovement = 0.0f;
 	}
 
 	if (camSetArrPos == 0 || camSetArrPos == 7) {
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index e5bc09c8..91dd6573 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -124,8 +124,8 @@ CCamera::Init(void)
 	m_WideScreenOn = false;
 	m_fFOV_Wide_Screen = 0.0f;
 	m_bRestoreByJumpCut = false;
-	CarZoomIndicator = 2.0f;
-	PedZoomIndicator = 2.0f;
+	CarZoomIndicator = CAM_ZOOM_2;
+	PedZoomIndicator = CAM_ZOOM_2;
 	CarZoomValueSmooth = 0.0f;
 	m_fPedZoomValueSmooth = 0.0f;
 	pTargetEntity = nil;
@@ -142,7 +142,7 @@ CCamera::Init(void)
 	PlayerExhaustion = 1.0f;
 	DebugCamMode = CCam::MODE_NONE;
 	m_PedOrientForBehindOrInFront = 0.0f;
-	if(!FrontEndMenuManager.m_bStartGameLoading){
+	if(!FrontEndMenuManager.m_bWantToRestart){
 		m_bFading = false;
 		CDraw::FadeValue = 0;
 		m_fFLOATingFade = 0.0f;
@@ -151,7 +151,7 @@ CCamera::Init(void)
 		m_fFLOATingFadeMusic = 0.0f;
 	}
 	m_bMoveCamToAvoidGeom = false;
-	if(FrontEndMenuManager.m_bStartGameLoading)
+	if(FrontEndMenuManager.m_bWantToRestart)
 		m_bMoveCamToAvoidGeom = true;
 	m_bStartingSpline = false;
 	m_iTypeOfSwitch = INTERPOLATION;
@@ -623,11 +623,11 @@ CCamera::CamControl(void)
 				if(CPad::GetPad(0)->CycleCameraModeUpJustDown() && !CReplay::IsPlayingBack() &&
 				   (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
 				   !m_WideScreenOn)
-					CarZoomIndicator -= 1.0f;
+					CarZoomIndicator--;
 				if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() &&
 				   (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
 				   !m_WideScreenOn)
-					CarZoomIndicator += 1.0f;
+					CarZoomIndicator++;
 				if(!m_bFailedCullZoneTestPreviously){
 					if(CarZoomIndicator < CAM_ZOOM_1STPRS) CarZoomIndicator = CAM_ZOOM_CINEMATIC;
 					else if(CarZoomIndicator > CAM_ZOOM_CINEMATIC) CarZoomIndicator = CAM_ZOOM_1STPRS;
@@ -727,12 +727,24 @@ CCamera::CamControl(void)
 				if(CarZoomIndicator == CAM_ZOOM_1STPRS && !m_bPlayerIsInGarage){
 					CarZoomValue = 0.0f;
 					ReqMode = CCam::MODE_1STPERSON;
-				}else if(CarZoomIndicator == CAM_ZOOM_1)
-					CarZoomValue = 0.05f;
+				}
+#ifdef FREE_CAM
+				else if (bFreeCam) {
+					if (CarZoomIndicator == CAM_ZOOM_1)
+						CarZoomValue = ((CVehicle*)pTargetEntity)->IsBoat() ? FREE_BOAT_ZOOM_VALUE_1 : FREE_CAR_ZOOM_VALUE_1;
+					else if (CarZoomIndicator == CAM_ZOOM_2)
+						CarZoomValue = ((CVehicle*)pTargetEntity)->IsBoat() ? FREE_BOAT_ZOOM_VALUE_2 : FREE_CAR_ZOOM_VALUE_2;
+					else if (CarZoomIndicator == CAM_ZOOM_3)
+						CarZoomValue = ((CVehicle*)pTargetEntity)->IsBoat() ? FREE_BOAT_ZOOM_VALUE_3 : FREE_CAR_ZOOM_VALUE_3;
+				}
+#endif
+				else if(CarZoomIndicator == CAM_ZOOM_1)
+					CarZoomValue = DEFAULT_CAR_ZOOM_VALUE_1;
 				else if(CarZoomIndicator == CAM_ZOOM_2)
-					CarZoomValue = 1.9f;
+					CarZoomValue = DEFAULT_CAR_ZOOM_VALUE_2;
 				else if(CarZoomIndicator == CAM_ZOOM_3)
-					CarZoomValue = 3.9f;
+					CarZoomValue = DEFAULT_CAR_ZOOM_VALUE_3;
+
 				if(CarZoomIndicator == CAM_ZOOM_TOPDOWN && !m_bPlayerIsInGarage){
 					CarZoomValue = 1.0f;
 					ReqMode = CCam::MODE_TOPDOWN;
@@ -800,7 +812,7 @@ CCamera::CamControl(void)
 					else
 						PedZoomIndicator = CAM_ZOOM_TOPDOWN;
 				}else
-					PedZoomIndicator -= 1.0f;
+					PedZoomIndicator--;
 			}
 			if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() &&
 			   (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
@@ -811,7 +823,7 @@ CCamera::CamControl(void)
 					else
 						PedZoomIndicator = CAM_ZOOM_TOPDOWN;
 				}else
-					PedZoomIndicator += 1.0f;
+					PedZoomIndicator++;
 			}
 			// disabled obbe's cam here
 			if(PedZoomIndicator < CAM_ZOOM_1) PedZoomIndicator = CAM_ZOOM_TOPDOWN;
@@ -1211,7 +1223,7 @@ CCamera::CamControl(void)
 	   ReqMode == CCam::MODE_1STPERSON_RUNABOUT || ReqMode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
 	   ReqMode == CCam::MODE_FIGHT_CAM_RUNABOUT || ReqMode == CCam::MODE_HELICANNON_1STPERSON ||
 	   WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT ||
-           m_bJustCameOutOfGarage || m_bPlayerIsInGarage)
+	   m_bJustCameOutOfGarage || m_bPlayerIsInGarage)
 		canUseObbeCam = false;
 
 	if(m_bObbeCinematicPedCamOn && canUseObbeCam)
@@ -1512,7 +1524,7 @@ CCamera::UpdateTargetEntity(void)
 			cantOpen = false;
 
 		if(PLAYER->GetPedState() == PED_ENTER_CAR && !cantOpen){
-			if(!enteringCar && CarZoomIndicator != 0.0f){
+			if(!enteringCar && CarZoomIndicator != CAM_ZOOM_1STPRS){
 				pTargetEntity = PLAYER->m_pMyVehicle;
 				if(PLAYER->m_pMyVehicle == nil)
 					pTargetEntity = PLAYER;
@@ -1520,7 +1532,7 @@ CCamera::UpdateTargetEntity(void)
 		}
 
 		if((PLAYER->GetPedState() == PED_CARJACK || PLAYER->GetPedState() == PED_OPEN_DOOR) && !cantOpen){
-			if(!enteringCar && CarZoomIndicator != 0.0f)
+			if(!enteringCar && CarZoomIndicator != CAM_ZOOM_1STPRS)
 #ifdef GTA_PS2_STUFF
 // dunno if this has any amazing effects
 			{
@@ -1537,7 +1549,7 @@ CCamera::UpdateTargetEntity(void)
 			pTargetEntity = FindPlayerPed();
 		if(PLAYER->GetPedState() == PED_DRAG_FROM_CAR)
 			pTargetEntity = FindPlayerPed();
-		if(pTargetEntity->IsVehicle() && CarZoomIndicator != 0.0f && FindPlayerPed()->GetPedState() == PED_ARRESTED)
+		if(pTargetEntity->IsVehicle() && CarZoomIndicator != CAM_ZOOM_1STPRS && FindPlayerPed()->GetPedState() == PED_ARRESTED)
 			pTargetEntity = FindPlayerPed();
 	}
 }
@@ -2956,11 +2968,23 @@ CCamera::SetZoomValueFollowPedScript(int16 dist)
 void
 CCamera::SetZoomValueCamStringScript(int16 dist)
 {
-	switch (dist) {
-	case 0: m_fCarZoomValueScript = 0.05f; break;
-	case 1: m_fCarZoomValueScript = 1.9f; break;
-	case 2: m_fCarZoomValueScript = 3.9f; break;
-	default: m_fCarZoomValueScript = m_fCarZoomValueScript; break;
+#ifdef FREE_CAM
+	if (bFreeCam) {
+		switch (dist) {
+		case 0: m_fCarZoomValueScript = ((CVehicle*)Cams[ActiveCam].CamTargetEntity)->IsBoat() ? FREE_BOAT_ZOOM_VALUE_1 : FREE_CAR_ZOOM_VALUE_1; break;
+		case 1: m_fCarZoomValueScript = ((CVehicle*)Cams[ActiveCam].CamTargetEntity)->IsBoat() ? FREE_BOAT_ZOOM_VALUE_2 : FREE_CAR_ZOOM_VALUE_2; break;
+		case 2: m_fCarZoomValueScript = ((CVehicle*)Cams[ActiveCam].CamTargetEntity)->IsBoat() ? FREE_BOAT_ZOOM_VALUE_3 : FREE_CAR_ZOOM_VALUE_3; break;
+		default: m_fCarZoomValueScript = m_fCarZoomValueScript; break;
+		}
+	} else
+#endif
+	{
+		switch (dist) {
+		case 0: m_fCarZoomValueScript = DEFAULT_CAR_ZOOM_VALUE_1; break;
+		case 1: m_fCarZoomValueScript = DEFAULT_CAR_ZOOM_VALUE_2; break;
+		case 2: m_fCarZoomValueScript = DEFAULT_CAR_ZOOM_VALUE_3; break;
+		default: m_fCarZoomValueScript = m_fCarZoomValueScript; break;
+		}
 	}
 
 	m_bUseScriptZoomValueCar = true;
@@ -3245,7 +3269,7 @@ void
 CCamera::SetRwCamera(RwCamera *cam)
 {
 	m_pRwCamera = cam;
-	m_viewMatrix.Attach(&m_pRwCamera->viewMatrix, false);
+	m_viewMatrix.Attach(RwCameraGetViewMatrix(m_pRwCamera), false);
 	CMBlur::MotionBlurOpen(m_pRwCamera);
 }
 
diff --git a/src/core/Camera.h b/src/core/Camera.h
index f21fe913..eca4518a 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -16,12 +16,29 @@ enum
 };
 
 #define DEFAULT_NEAR (0.9f)
-#define CAM_ZOOM_1STPRS (0.0f)
-#define CAM_ZOOM_1 (1.0f)
-#define CAM_ZOOM_2 (2.0f)
-#define CAM_ZOOM_3 (3.0f)
-#define CAM_ZOOM_TOPDOWN (4.0f)
-#define CAM_ZOOM_CINEMATIC (5.0f)
+enum
+{
+	CAM_ZOOM_1STPRS,
+	CAM_ZOOM_1,
+	CAM_ZOOM_2,
+	CAM_ZOOM_3,
+	CAM_ZOOM_TOPDOWN,
+	CAM_ZOOM_CINEMATIC,
+};
+
+#ifdef FREE_CAM // LCS values
+#define FREE_CAR_ZOOM_VALUE_1 (-1.0f)
+#define FREE_CAR_ZOOM_VALUE_2 (2.0f)
+#define FREE_CAR_ZOOM_VALUE_3 (6.0f)
+
+#define FREE_BOAT_ZOOM_VALUE_1 (-2.41f)
+#define FREE_BOAT_ZOOM_VALUE_2 (6.49f)
+#define FREE_BOAT_ZOOM_VALUE_3 (15.0f)
+#endif
+
+#define DEFAULT_CAR_ZOOM_VALUE_1 (0.05f)
+#define DEFAULT_CAR_ZOOM_VALUE_2 (1.9f)
+#define DEFAULT_CAR_ZOOM_VALUE_3 (3.9f)
 
 class CCam
 {
@@ -398,7 +415,11 @@ uint32    unknown;	// some counter having to do with music
 
 	float CamFrontXNorm;
 	float CamFrontYNorm;
+#if 0  // TODO: FIX_BUGS once GenericLoad is done
+	int32 CarZoomIndicator;
+#else
 	float CarZoomIndicator;
+#endif
 	float CarZoomValue;
 	float CarZoomValueSmooth;
 
@@ -434,7 +455,11 @@ uint32    unknown;	// some counter having to do with music
 	float m_ScreenReductionSpeed;
 	float m_AlphaForPlayerAnim1rstPerson;
 	float Orientation;
+#if 0  // TODO: FIX_BUGS once GenericLoad is done
+	int32 PedZoomIndicator;
+#else
 	float PedZoomIndicator;
+#endif
 	float PlayerExhaustion;
 	float SoundDistUp, SoundDistLeft, SoundDistRight;
 	float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead;
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index 94ef769e..c884f751 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -34,8 +34,6 @@ enum Direction
 eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250;
 CLinkList<CColModel*> &CCollision::ms_colModelCache = *(CLinkList<CColModel*>*)0x95CB58;
 
-WRAPPER bool CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly) { EAXJMP(0x4105A0); }
-
 void
 CCollision::Init(void)
 {
@@ -926,6 +924,87 @@ CCollision::ProcessVerticalLineTriangle(const CColLine &line,
 	return true;
 }
 
+bool
+CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly)
+{
+	float t;
+
+	if(!poly->valid)
+		return false;
+
+	// maybe inlined?
+	CColTriangle tri;
+	tri.a = 0;
+	tri.b = 1;
+	tri.c = 2;
+	CColTrianglePlane plane;
+	plane.Set(poly->verts, tri);
+
+	const CVector &va = poly->verts[tri.a];
+	const CVector &vb = poly->verts[tri.b];
+	const CVector &vc = poly->verts[tri.c];
+	CVector p0 = pos;
+	CVector p1(pos.x, pos.y, z);
+
+	// The rest is pretty much CCollision::ProcessLineTriangle
+
+	// if points are on the same side, no collision
+	if(plane.CalcPoint(p0) * plane.CalcPoint(p1) > 0.0f)
+		return poly->valid = false;
+
+	// intersection parameter on line
+	t = -plane.CalcPoint(p0) / DotProduct(p1 - p0, plane.normal);
+	// find point of intersection
+	CVector p = p0 + (p1-p0)*t;
+
+	CVector2D vec1, vec2, vec3, vect;
+	switch(plane.dir){
+	case DIR_X_POS:
+		vec1.x = va.y; vec1.y = va.z;
+		vec2.x = vc.y; vec2.y = vc.z;
+		vec3.x = vb.y; vec3.y = vb.z;
+		vect.x = p.y; vect.y = p.z;
+		break;
+	case DIR_X_NEG:
+		vec1.x = va.y; vec1.y = va.z;
+		vec2.x = vb.y; vec2.y = vb.z;
+		vec3.x = vc.y; vec3.y = vc.z;
+		vect.x = p.y; vect.y = p.z;
+		break;
+	case DIR_Y_POS:
+		vec1.x = va.z; vec1.y = va.x;
+		vec2.x = vc.z; vec2.y = vc.x;
+		vec3.x = vb.z; vec3.y = vb.x;
+		vect.x = p.z; vect.y = p.x;
+		break;
+	case DIR_Y_NEG:
+		vec1.x = va.z; vec1.y = va.x;
+		vec2.x = vb.z; vec2.y = vb.x;
+		vec3.x = vc.z; vec3.y = vc.x;
+		vect.x = p.z; vect.y = p.x;
+		break;
+	case DIR_Z_POS:
+		vec1.x = va.x; vec1.y = va.y;
+		vec2.x = vc.x; vec2.y = vc.y;
+		vec3.x = vb.x; vec3.y = vb.y;
+		vect.x = p.x; vect.y = p.y;
+		break;
+	case DIR_Z_NEG:
+		vec1.x = va.x; vec1.y = va.y;
+		vec2.x = vb.x; vec2.y = vb.y;
+		vec3.x = vc.x; vec3.y = vc.y;
+		vect.x = p.x; vect.y = p.y;
+		break;
+	default:
+		assert(0);
+	}
+	if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return poly->valid = false;
+	if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return poly->valid = false;
+	if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return poly->valid = false;
+	point.point = p;
+	return poly->valid = true;
+}
+
 bool
 CCollision::ProcessLineTriangle(const CColLine &line ,
 	const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
diff --git a/src/core/Collision.h b/src/core/Collision.h
index 429fc17f..1cbd1690 100644
--- a/src/core/Collision.h
+++ b/src/core/Collision.h
@@ -144,7 +144,6 @@ public:
 	static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough);
 	static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly);
 	static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists);
-	// TODO:
 	static bool IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly);
 
 	static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point);
diff --git a/src/core/Debug.cpp b/src/core/Debug.cpp
index 2b713198..917c99ab 100644
--- a/src/core/Debug.cpp
+++ b/src/core/Debug.cpp
@@ -24,7 +24,7 @@ CDebug::DebugAddText(const char *str)
 {
 	int32 i = 0;
 	if (*str != '\0') {
-		while (i < MAX_STR_LEN) {
+		while (i < MAX_STR_LEN - 1) {
 			ms_aTextBuffer[ms_nCurrentTextLine][i++] = *(str++);
 			if (*str == '\0')
 				break;
diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp
index 6305bf33..e0a0fafc 100644
--- a/src/core/FileLoader.cpp
+++ b/src/core/FileLoader.cpp
@@ -25,8 +25,6 @@
 #include "CdStream.h"
 #include "FileLoader.h"
 
-WRAPPER void CFileLoader::ReloadPaths(const char *filename) { EAXJMP(0x476DB0); }
-
 char CFileLoader::ms_line[256];
 
 const char*
@@ -311,7 +309,7 @@ CFileLoader::FindRelatedModelInfoCB(RpAtomic *atomic, void *data)
 	int n;
 	RpClump *clump = (RpClump*)data;
 
-	nodename = GetFrameNodeName(RpClumpGetFrame(atomic));
+	nodename = GetFrameNodeName(RpAtomicGetFrame(atomic));
 	GetNameAndLOD(nodename, name, &n);
 	mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(name, nil);
 	if(mi){
@@ -1198,6 +1196,165 @@ CFileLoader::LoadMapZones(const char *filename)
 	debug("Finished loading IPL\n");
 }
 
+void
+CFileLoader::ReloadPaths(const char *filename)
+{
+	enum {
+		NONE,
+		PATH,
+	};
+	char *line;
+	int section = NONE;
+	int id, pathType, pathIndex = -1;
+	char pathTypeStr[20];
+	debug("Reloading paths from %s...\n", filename);
+
+	int fd = CFileMgr::OpenFile(filename, "r");
+	for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) {
+		if (*line == '\0' || *line == '#')
+			continue;
+
+		if (section == NONE) {
+			if (strncmp(line, "path", 4) == 0) {
+				section = PATH;
+				ThePaths.AllocatePathFindInfoMem(4500);
+			}
+		} else if (strncmp(line, "end", 3) == 0) {
+			section = NONE;
+		} else {
+			switch (section) {
+				case PATH:
+					if (pathIndex == -1) {
+						id = LoadPathHeader(line, pathTypeStr);
+						if (strncmp(pathTypeStr, "ped", 4) == 0)
+							pathType = 1;
+						else if (strncmp(pathTypeStr, "car", 4) == 0)
+							pathType = 0;
+						pathIndex = 0;
+					} else {
+						if (pathType == 1)
+							LoadPedPathNode(line, id, pathIndex);
+						else if (pathType == 0)
+							LoadCarPathNode(line, id, pathIndex);
+						pathIndex++;
+						if (pathIndex == 12)
+							pathIndex = -1;
+					}
+					break;
+				default:
+					break;
+			}
+		}
+	}
+	CFileMgr::CloseFile(fd);
+}
+
+void
+CFileLoader::ReloadObjectTypes(const char *filename)
+{
+	enum {
+		NONE,
+		OBJS,
+		TOBJ,
+		TWODFX
+	};
+	char *line;
+	int section = NONE;
+	CModelInfo::ReInit2dEffects();
+	debug("Reloading object types from %s...\n", filename);
+
+	CFileMgr::ChangeDir("\\DATA\\MAPS\\");
+	int fd = CFileMgr::OpenFile(filename, "r");
+	CFileMgr::ChangeDir("\\");
+	for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) {
+		if (*line == '\0' || *line == '#')
+			continue;
+
+		if (section == NONE) {
+			if (strncmp(line, "objs", 4) == 0) section = OBJS;
+			else if (strncmp(line, "tobj", 4) == 0) section = TOBJ;
+			else if (strncmp(line, "2dfx", 4) == 0) section = TWODFX;
+		} else if (strncmp(line, "end", 3) == 0) {
+			section = NONE;
+		} else {
+			switch (section) {
+				case OBJS:
+				case TOBJ:
+					ReloadObject(line);
+					break;
+				case TWODFX:
+					Load2dEffect(line);
+					break;
+				default:
+					break;
+			}
+		}
+	}
+	CFileMgr::CloseFile(fd);
+}
+
+void
+CFileLoader::ReloadObject(const char *line)
+{
+	int id, numObjs;
+	char model[24], txd[24];
+	float dist[3];
+	uint32 flags;
+	CSimpleModelInfo *mi;
+
+	if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4)
+		return;
+
+	switch(numObjs){
+	case 1:
+		sscanf(line, "%d %s %s %d %f %d",
+			&id, model, txd, &numObjs, &dist[0], &flags);
+		break;
+	case 2:
+		sscanf(line, "%d %s %s %d %f %f %d",
+			&id, model, txd, &numObjs, &dist[0], &dist[1], &flags);
+		break;
+	case 3:
+		sscanf(line, "%d %s %s %d %f %f %f %d",
+			&id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags);
+		break;
+	}
+
+	mi = (CSimpleModelInfo*) CModelInfo::GetModelInfo(id);
+	if (
+#ifdef FIX_BUGS
+		mi &&
+#endif
+		mi->m_type == MITYPE_SIMPLE && !strcmp(mi->GetName(), model) && mi->m_numAtomics == numObjs) {
+		mi->SetLodDistances(dist);
+		SetModelInfoFlags(mi, flags);
+	} else {
+		printf("Can't reload %s\n", model);
+	}
+}
+
+// unused mobile function - crashes
+void
+CFileLoader::ReLoadScene(const char *filename)
+{
+	char *line;
+	CFileMgr::ChangeDir("\\DATA\\");
+	int fd = CFileMgr::OpenFile(filename, "r");
+	CFileMgr::ChangeDir("\\");
+
+	for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) {
+		if (*line == '#')
+			continue;
+
+		if (strncmp(line, "EXIT", 9) == 0)	// BUG: 9?
+			break;
+
+		if (strncmp(line, "IDE", 3) == 0) {
+			LoadObjectTypes(line + 4);
+		}
+	}
+	CFileMgr::CloseFile(fd);
+}
 
 STARTPATCHES
 	InjectHook(0x476290, CFileLoader::LoadLevel, PATCH_JUMP);
@@ -1233,4 +1390,8 @@ STARTPATCHES
 	InjectHook(0x478A90, CFileLoader::LoadCullZone, PATCH_JUMP);
 
 	InjectHook(0x478550, CFileLoader::LoadMapZones, PATCH_JUMP);
+
+	InjectHook(0x476DB0, CFileLoader::ReloadPaths, PATCH_JUMP);
+	InjectHook(0x476F30, CFileLoader::ReloadObjectTypes, PATCH_JUMP);
+	InjectHook(0x4772B0, CFileLoader::ReloadObject, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/core/FileLoader.h b/src/core/FileLoader.h
index 1b390279..87b8fe61 100644
--- a/src/core/FileLoader.h
+++ b/src/core/FileLoader.h
@@ -43,4 +43,7 @@ public:
 	static void LoadMapZones(const char *filename);
 
 	static void ReloadPaths(const char *filename);
+	static void ReloadObjectTypes(const char *filename);
+	static void ReloadObject(const char *line);
+	static void ReLoadScene(const char *filename); // unused mobile function
 };
diff --git a/src/core/FrontEndControls.cpp b/src/core/FrontEndControls.cpp
new file mode 100644
index 00000000..866be42f
--- /dev/null
+++ b/src/core/FrontEndControls.cpp
@@ -0,0 +1,1881 @@
+#include "common.h"
+#include "main.h"
+#include "Timer.h"
+#include "Pad.h"
+#include "ControllerConfig.h"
+#include "VisibilityPlugins.h"
+#include "Sprite2d.h"
+#include "Text.h"
+#include "Font.h"
+#include "Frontend.h"
+#include "FrontEndControls.h"
+
+
+void
+CPlaceableShText::Draw(float x, float y)
+{
+	if(m_text == nil)
+		return;
+
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOn();
+	if(m_bDropShadow){
+		CFont::SetDropShadowPosition(m_shadowOffset.x);
+		CFont::SetDropColor(m_shadowColor);
+	}
+	CFont::SetColor(m_color);
+	CFont::PrintString(x+m_position.x, y+m_position.y, m_text);
+	if(m_bDropShadow)
+		CFont::SetDropShadowPosition(0);
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOff();
+}
+
+void
+CPlaceableShText::Draw(const CRGBA &color, float x, float y)
+{
+	if(m_text == nil)
+		return;
+
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOn();
+	if(m_bDropShadow){
+		CFont::SetDropShadowPosition(m_shadowOffset.x);
+		CFont::SetDropColor(m_shadowColor);
+	}
+	CFont::SetColor(color);
+	CFont::PrintString(x+m_position.x, y+m_position.y, m_text);
+	if(m_bDropShadow)
+		CFont::SetDropShadowPosition(0);
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOff();
+}
+
+void
+CPlaceableShTextTwoLines::Draw(float x, float y)
+{
+	if(m_line1.m_text == nil && m_line2.m_text == nil)
+		return;
+
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOn();
+	if(m_bDropShadow){
+		CFont::SetDropShadowPosition(m_shadowOffset.x);
+		CFont::SetDropColor(m_shadowColor);
+	}
+
+	if(m_line1.m_text){
+		CFont::SetColor(m_line1.m_color);
+		CFont::PrintString(x+m_line1.m_position.x, y+m_line1.m_position.y, m_line1.m_text);
+	}
+	if(m_line2.m_text){
+		CFont::SetColor(m_line2.m_color);
+		CFont::PrintString(x+m_line2.m_position.x, y+m_line2.m_position.y, m_line2.m_text);
+	}
+
+	if(m_bDropShadow)
+		CFont::SetDropShadowPosition(0);
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOff();
+}
+
+void
+CPlaceableShTextTwoLines::Draw(const CRGBA &color, float x, float y)
+{
+	if(m_line1.m_text == nil && m_line2.m_text == nil)
+		return;
+
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOn();
+	if(m_bDropShadow){
+		CFont::SetDropShadowPosition(m_shadowOffset.x);
+		CFont::SetDropColor(m_shadowColor);
+	}
+
+	if(m_line1.m_text){
+		CFont::SetColor(color);
+		CFont::PrintString(x+m_line1.m_position.x, y+m_line1.m_position.y, m_line1.m_text);
+	}
+	if(m_line2.m_text){
+		CFont::SetColor(color);
+		CFont::PrintString(x+m_line2.m_position.x, y+m_line2.m_position.y, m_line2.m_text);
+	}
+
+	if(m_bDropShadow)
+		CFont::SetDropShadowPosition(0);
+	if(m_bRightJustify)
+		CFont::SetRightJustifyOff();
+}
+
+void
+CPlaceableShOption::Draw(const CRGBA &highlightColor, float x, float y, bool bHighlight)
+{
+	if(bHighlight)
+		CPlaceableShText::Draw(highlightColor, x, y);
+	else if(m_bSelected)
+		CPlaceableShText::Draw(m_selectedColor, x, y);
+	else
+		CPlaceableShText::Draw(x, y);
+}
+
+void
+CPlaceableShOptionTwoLines::Draw(const CRGBA &highlightColor, float x, float y, bool bHighlight)
+{
+	if(bHighlight)
+		CPlaceableShTextTwoLines::Draw(highlightColor, x, y);
+	else if(m_bSelected)
+		CPlaceableShTextTwoLines::Draw(m_selectedColor, x, y);
+	else
+		CPlaceableShTextTwoLines::Draw(x, y);
+}
+
+void
+CPlaceableSprite::Draw(float x, float y)
+{
+	Draw(m_color, x, y);
+}
+
+void
+CPlaceableSprite::Draw(const CRGBA &color, float x, float y)
+{
+	if(m_pSprite)
+		m_pSprite->Draw(CRect(m_position.x+x, m_position.y+y,
+		                      m_position.x+x + m_size.x, m_position.y+y + m_size.y),
+		                color);
+}
+
+void
+CPlaceableShSprite::Draw(float x, float y)
+{
+	if(m_bDropShadow)
+		m_shadow.Draw(m_shadow.m_color, m_sprite.m_position.x+x, m_sprite.m_position.y+y);
+	m_sprite.Draw(x, y);
+}
+
+
+/*
+ * CMenuPictureAndText
+ */
+
+void
+CMenuPictureAndText::SetNewOldShadowWrapX(bool bWrapX, float newWrapX, float oldWrapX)
+{
+	m_bWrap = bWrapX;
+	m_wrapX = newWrapX;
+	m_oldWrapx = oldWrapX;
+}
+
+void
+CMenuPictureAndText::SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale)
+{
+	m_bSetTextScale = bTextScale;
+	m_textScale = newScale;
+	m_oldTextScale = oldScale;
+}
+
+void
+CMenuPictureAndText::SetTextsColor(CRGBA const &color)
+{
+	int i;
+	for(i = 0; i < m_numTexts; i++)
+		m_texts[i].m_color = color;
+}
+
+void
+CMenuPictureAndText::AddText(wchar *text, float positionX, float positionY, CRGBA const &color, bool bRightJustify)
+{
+	int i;
+	if(m_numTexts >= 20)
+		return;
+	i = m_numTexts++;
+	m_texts[i].m_text = text;
+	m_texts[i].m_position.x = positionX;
+	m_texts[i].m_position.y = positionY;
+	m_texts[i].m_color = color;
+	m_texts[i].m_bRightJustify = bRightJustify;
+}
+
+void
+CMenuPictureAndText::AddPicture(CSprite2d *sprite, CSprite2d *shadow, float positionX, float positionY, float width, float height, CRGBA const &color)
+{
+	int i;
+	if(m_numSprites >= 5)
+		return;
+	i = m_numSprites++;
+	m_sprites[i].m_sprite.m_pSprite = sprite;
+	m_sprites[i].m_shadow.m_pSprite = shadow;
+	m_sprites[i].m_sprite.m_position.x = positionX;
+	m_sprites[i].m_sprite.m_position.y = positionY;
+	m_sprites[i].m_sprite.m_size.x = width;
+	m_sprites[i].m_sprite.m_size.y = height;
+	m_sprites[i].m_shadow.m_size.x = width;
+	m_sprites[i].m_shadow.m_size.y = height;
+	m_sprites[i].m_sprite.m_color = color;
+}
+
+void
+CMenuPictureAndText::AddPicture(CSprite2d *sprite, float positionX, float positionY, float width, float height, CRGBA const &color)
+{
+	int i;
+	if(m_numSprites >= 5)
+		return;
+	i = m_numSprites++;
+	m_sprites[i].m_sprite.m_pSprite = sprite;
+	m_sprites[i].m_shadow.m_pSprite = nil;
+	m_sprites[i].m_sprite.m_position.x = positionX;
+	m_sprites[i].m_sprite.m_position.y = positionY;
+	m_sprites[i].m_sprite.m_size.x = width;
+	m_sprites[i].m_sprite.m_size.y = height;
+	m_sprites[i].m_shadow.m_size.x = width;
+	m_sprites[i].m_shadow.m_size.y = height;
+	m_sprites[i].m_sprite.m_color = color;
+}
+
+void
+CMenuPictureAndText::Draw(CRGBA const &,CRGBA const &, float x, float y)
+{
+	int i;
+
+	for(i = 0; i < m_numSprites; i++)
+		m_sprites[i].Draw(m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	for(i = 0; i < m_numTexts; i++)
+		if(m_bWrap)
+			m_texts[i].DrawShWrap(m_position.x+x, m_position.y+y, m_wrapX, m_oldWrapx);
+		else
+			m_texts[i].Draw(m_position.x+x, m_position.y+y);
+	if(m_bSetTextScale)
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+}
+
+void
+CMenuPictureAndText::SetAlpha(uint8 alpha)
+{
+	int i;
+
+	for(i = 0; i < m_numSprites; i++)
+		m_sprites[i].SetAlpha(alpha);
+	for(i = 0; i < m_numTexts; i++)
+		m_texts[i].SetAlpha(alpha);
+}
+
+void
+CMenuPictureAndText::SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset)
+{
+	int i;
+
+	for(i = 0; i < 5; i++)
+		m_sprites[i].SetShadows(bDropShadows, shadowColor, shadowOffset);
+	for(i = 0; i < 20; i++)
+		m_texts[i].SetShadows(bDropShadows, shadowColor, shadowOffset);
+}
+
+/*
+ * CMenuMultiChoice
+ */
+
+void
+CMenuMultiChoice::AddTitle(wchar *text, float positionX, float positionY, bool bRightJustify)
+{
+	m_title.m_text = text;
+	m_title.SetPosition(positionX, positionY, bRightJustify);
+}
+
+CPlaceableShOption*
+CMenuMultiChoice::AddOption(wchar *text, float positionX, float positionY, bool bSelected, bool bRightJustify)
+{
+	if(m_numOptions == NUM_MULTICHOICE_OPTIONS)
+		return nil;
+	m_options[m_numOptions].m_text = text;
+	m_options[m_numOptions].SetPosition(positionX, positionY);
+	m_options[m_numOptions].m_bSelected = bSelected;
+	m_options[m_numOptions].m_bRightJustify = bRightJustify;
+	return &m_options[m_numOptions++];
+}
+
+void
+CMenuMultiChoice::SetColors(const CRGBA &title, const CRGBA &normal, const CRGBA &selected)
+{
+	int i;
+	m_title.SetColor(title);
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].SetColors(normal, selected);
+}
+
+void
+CMenuMultiChoice::SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale)
+{
+	m_bSetTextScale = bTextScale;
+	m_textScale = newScale;
+	m_oldTextScale = oldScale;
+	m_bSetTitleTextScale = bTitleTextScale;
+}
+
+void
+CMenuMultiChoice::Draw(CRGBA const &optionHighlight ,CRGBA const &titleHighlight, float x, float y)
+{
+	int i;
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	if(m_cursor == -1)
+		m_title.Draw(m_position.x+x, m_position.y+y);
+	else
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	if(m_cursor == -1)
+		for(i = 0; i < m_numOptions; i++)
+			m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+	else
+		for(i = 0; i < m_numOptions; i++){
+			if(i == m_cursor)
+				m_options[i].Draw(optionHighlight, m_position.x+x, m_position.y+y);
+			else
+				m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+		}
+
+	if(m_bSetTextScale){
+		CFont::DrawFonts();
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+	}
+}
+
+void
+CMenuMultiChoice::DrawNormal(float x, float y)
+{
+	int i;
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	m_title.Draw(m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	for(i = 0; i < m_numOptions; i++)
+		m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+
+	if(m_bSetTextScale){
+		CFont::DrawFonts();
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+	}
+}
+
+void
+CMenuMultiChoice::DrawHighlighted(CRGBA const &titleHighlight, float x, float y)
+{
+	int i;
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	if(m_cursor == -1)
+		m_title.Draw(m_position.x+x, m_position.y+y);
+	else
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	for(i = 0; i < m_numOptions; i++)
+		m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+
+	if(m_bSetTextScale){
+		CFont::DrawFonts();
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+	}
+}
+
+void
+CMenuMultiChoice::SetAlpha(uint8 alpha)
+{
+	int i;
+	m_title.SetAlpha(alpha);
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].SetAlpha(alpha);
+}
+
+void
+CMenuMultiChoice::SetShadows(bool bDropShadows, CRGBA const &shadowColor, CVector2D const &shadowOffset)
+{
+	int i;
+	m_title.SetShadows(bDropShadows, shadowColor, shadowOffset);
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].SetShadows(bDropShadows, shadowColor, shadowOffset);
+}
+
+
+bool
+CMenuMultiChoice::GoNext(void)
+{
+	if(m_cursor == m_numOptions-1){
+		m_cursor = -1;
+		return false;
+	}else{
+		m_cursor++;
+		return true;
+	}
+}
+
+bool
+CMenuMultiChoice::GoPrev(void)
+{
+	if(m_cursor == 0){
+		m_cursor = -1;
+		return false;
+	}else{
+		m_cursor--;
+		return true;
+	}
+}
+
+void
+CMenuMultiChoice::SelectCurrentOptionUnderCursor(void)
+{
+	int i;
+	if(m_cursor == -1)
+		return;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].m_bSelected = false;
+	m_options[m_cursor].m_bSelected = true;
+}
+
+int
+CMenuMultiChoice::GetMenuSelection(void)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		if(m_options[i].m_bSelected)
+			return i;
+	return -1;
+}
+
+void
+CMenuMultiChoice::SetMenuSelection(int selection)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].m_bSelected = false;
+	m_options[selection%NUM_MULTICHOICE_OPTIONS].m_bSelected = true;
+}
+
+/*
+ * CMenuMultiChoiceTriggered
+ */
+
+void
+CMenuMultiChoiceTriggered::Initialise(void)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_triggers[i] = nil;
+	m_defaultCancel = nil;
+}
+
+CPlaceableShOption*
+CMenuMultiChoiceTriggered::AddOption(wchar *text, float positionX, float positionY, Trigger trigger, bool bSelected, bool bRightJustify)
+{
+	CPlaceableShOption *option;
+	option = CMenuMultiChoice::AddOption(text, positionX, positionY, bSelected, bRightJustify);
+	if(option)
+		m_triggers[m_numOptions-1] = trigger;
+	return option;
+}
+
+void
+CMenuMultiChoiceTriggered::SelectCurrentOptionUnderCursor(void)
+{
+	CMenuMultiChoice::SelectCurrentOptionUnderCursor();
+	if(m_cursor != -1)
+		m_triggers[m_cursor](this);
+}
+
+void
+CMenuMultiChoiceTriggered::SelectDefaultCancelAction(void)
+{
+	if(m_defaultCancel)
+		m_defaultCancel(this);
+}
+
+/*
+ * CMenuMultiChoiceTriggeredAlways
+ */
+
+void
+CMenuMultiChoiceTriggeredAlways::Draw(CRGBA const &optionHighlight, CRGBA const &titleHighlight, float x, float y)
+{
+	if(m_alwaysTrigger)
+		m_alwaysTrigger(this);
+	CMenuMultiChoiceTriggered::Draw(optionHighlight, titleHighlight, x, y);
+}
+
+void
+CMenuMultiChoiceTriggeredAlways::DrawNormal(float x, float y)
+{
+	if(m_alwaysNormalTrigger)
+		m_alwaysNormalTrigger(this);
+	CMenuMultiChoiceTriggered::DrawNormal(x, y);
+}
+
+void
+CMenuMultiChoiceTriggeredAlways::DrawHighlighted(CRGBA const &titleHighlight, float x, float y)
+{
+	if(m_alwaysHighlightTrigger)
+		m_alwaysHighlightTrigger(this);
+	CMenuMultiChoiceTriggered::DrawHighlighted(titleHighlight, x, y);
+}
+
+/*
+ * CMenuMultiChoicePictured
+ */
+
+void
+CMenuMultiChoicePictured::Initialise(void)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_bHasSprite[i] = false;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_sprites[i].m_pSprite = nil;
+}
+
+CPlaceableShOption*
+CMenuMultiChoicePictured::AddOption(CSprite2d *sprite, float positionX, float positionY, const CVector2D &size, bool bSelected)
+{
+	CPlaceableShOption *option;
+	option = CMenuMultiChoice::AddOption(nil, 0.0f, 0.0f, bSelected, false);
+	if(option){
+		m_sprites[m_numOptions-1].m_pSprite = sprite;
+		m_sprites[m_numOptions-1].SetPosition(positionX, positionY);
+		m_sprites[m_numOptions-1].m_size = size;
+		m_bHasSprite[m_numOptions-1] = true;
+	}
+	return option;
+}
+
+void
+CMenuMultiChoicePictured::Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y)
+{
+	int i;
+
+	// The title and all the text
+	CMenuMultiChoice::Draw(optionHighlight, titleHighlight, x, y);
+
+	CRGBA selectedColor = m_options[0].GetSelectedColor();
+	CRGBA color = m_options[0].GetColor();
+
+	// The sprites
+	if(m_cursor == -1){
+		for(i = 0; i < m_numOptions; i++)
+			if(m_bHasSprite[i]){
+				if(m_options[i].m_bSelected)
+					m_sprites[i].Draw(selectedColor, m_position.x+x, m_position.y+y);
+				else
+					m_sprites[i].Draw(color, m_position.x+x, m_position.y+y);
+			}
+	}else{
+		for(i = 0; i < m_numOptions; i++)
+			if(i == m_cursor){
+				if(m_bHasSprite[i])
+					m_sprites[i].Draw(CRGBA(255, 255, 255, 255), m_position.x+x, m_position.y+y);
+			}else{
+				if(m_bHasSprite[i]){
+					if(m_options[i].m_bSelected)
+						m_sprites[i].Draw(selectedColor, m_position.x+x, m_position.y+y);
+					else
+						m_sprites[i].Draw(color, m_position.x+x, m_position.y+y);
+				}
+			}
+	}
+}
+
+void
+CMenuMultiChoicePictured::DrawNormal(float x, float y)
+{
+	int i;
+
+	// The title and all the text
+	CMenuMultiChoice::DrawNormal(x, y);
+
+	CRGBA selectedColor = m_options[0].GetSelectedColor();
+	CRGBA color = m_options[0].GetColor();
+
+	// The sprites
+	for(i = 0; i < m_numOptions; i++)
+		if(m_bHasSprite[i]){
+			if(m_options[i].m_bSelected)
+				m_sprites[i].Draw(selectedColor, m_position.x+x, m_position.y+y);
+			else
+				m_sprites[i].Draw(color, m_position.x+x, m_position.y+y);
+		}
+}
+
+void
+CMenuMultiChoicePictured::DrawHighlighted(const CRGBA &titleHighlight, float x, float y)
+{
+	int i;
+
+	// The title and all the text
+	CMenuMultiChoice::DrawHighlighted(titleHighlight, x, y);
+
+	CRGBA selectedColor = m_options[0].GetSelectedColor();
+	CRGBA color = m_options[0].GetColor();
+
+	// The sprites
+	for(i = 0; i < m_numOptions; i++)
+		if(m_bHasSprite[i]){
+			if(m_options[i].m_bSelected)
+				m_sprites[i].Draw(selectedColor, m_position.x+x, m_position.y+y);
+			else
+				m_sprites[i].Draw(color, m_position.x+x, m_position.y+y);
+		}
+}
+
+void
+CMenuMultiChoicePictured::SetAlpha(uint8 alpha)
+{
+	int i;
+	CMenuMultiChoice::SetAlpha(alpha);
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_sprites[i].SetAlpha(alpha);
+
+}
+
+
+/*
+ * CMenuMultiChoicePicturedTriggered
+ */
+
+void
+CMenuMultiChoicePicturedTriggered::Initialise(void)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_triggers[i] = nil;
+	m_defaultCancel = nil;	// missing on PS2
+}
+
+CPlaceableShOption*
+CMenuMultiChoicePicturedTriggered::AddOption(CSprite2d *sprite, float positionX, float positionY, const CVector2D &size, Trigger trigger, bool bSelected)
+{
+	CPlaceableShOption *option;
+	option = CMenuMultiChoicePictured::AddOption(sprite, positionX, positionY, size, bSelected);
+	if(option)
+		m_triggers[m_numOptions-1] = trigger;
+	return option;
+}
+
+void
+CMenuMultiChoicePicturedTriggered::SelectCurrentOptionUnderCursor(void)
+{
+	CMenuMultiChoice::SelectCurrentOptionUnderCursor();
+	if(m_cursor != -1)
+		m_triggers[m_cursor](this);
+}
+
+void
+CMenuMultiChoicePicturedTriggered::SelectDefaultCancelAction(void)
+{
+	if(m_defaultCancel)
+		m_defaultCancel(this);
+}
+
+/*
+ * CMenuMultiChoicePicturedTriggeredAnyMove
+ */
+
+void
+CMenuMultiChoicePicturedTriggeredAnyMove::Initialise(void)
+{
+	int i;
+	CMenuMultiChoicePicturedTriggered::Initialise();
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++){
+		m_moveTab[i].right = -1;
+		m_moveTab[i].left = -1;
+		m_moveTab[i].down = -1;
+		m_moveTab[i].up = -1;
+	}
+}
+
+CPlaceableShOption*
+CMenuMultiChoicePicturedTriggeredAnyMove::AddOption(CSprite2d *sprite, FEC_MOVETAB *moveTab, float positionX, float positionY, const CVector2D &size, Trigger trigger, bool bSelected)
+{
+	CPlaceableShOption *option;
+	option = CMenuMultiChoicePicturedTriggered::AddOption(sprite, positionX, positionY, size, trigger, bSelected);
+	if(option && moveTab)
+		m_moveTab[m_numOptions-1] = *moveTab;
+	return option;
+}
+
+bool
+CMenuMultiChoicePicturedTriggeredAnyMove::GoDown(void)
+{
+	int move = m_moveTab[m_cursor].down;
+	if(move == -1)
+		return GoNext();
+	m_cursor = move;
+	return true;
+}
+
+bool
+CMenuMultiChoicePicturedTriggeredAnyMove::GoUp(void)
+{
+	int move = m_moveTab[m_cursor].up;
+	if(move == -1)
+		return GoPrev();
+	m_cursor = move;
+	return true;
+}
+
+bool
+CMenuMultiChoicePicturedTriggeredAnyMove::GoLeft(void)
+{
+	int move = m_moveTab[m_cursor].left;
+	if(move == -1)
+		return GoPrev();
+	m_cursor = move;
+	return true;
+}
+
+bool
+CMenuMultiChoicePicturedTriggeredAnyMove::GoRight(void)
+{
+	int move = m_moveTab[m_cursor].right;
+	if(move == -1)
+		return GoNext();
+	m_cursor = move;
+	return true;
+}
+
+
+/*
+ * CMenuMultiChoiceTwoLines
+ */
+
+void
+CMenuMultiChoiceTwoLines::AddTitle(wchar *text, float positionX, float positionY, bool bRightJustify)
+{
+	m_title.m_text = text;
+	m_title.SetPosition(positionX, positionY, bRightJustify);
+}
+
+CPlaceableShOptionTwoLines*
+CMenuMultiChoiceTwoLines::AddOption(wchar *text, float positionX, float positionY, bool bSelected, bool bRightJustify)
+{
+	return AddOption(text, positionX, positionY, nil, 0.0f, 0.0f, bSelected, bRightJustify);
+}
+
+CPlaceableShOptionTwoLines*
+CMenuMultiChoiceTwoLines::AddOption(wchar *text1, float positionX1, float positionY1, wchar *text2, float positionX2, float positionY2, bool bSelected, bool bRightJustify)
+{
+	if(m_numOptions == NUM_MULTICHOICE_OPTIONS)
+		return nil;
+	m_options[m_numOptions].m_line1.m_text = text1;
+	m_options[m_numOptions].m_line2.m_text = text2;
+	m_options[m_numOptions].m_line1.SetPosition(positionX1, positionY1);
+	m_options[m_numOptions].m_line2.SetPosition(positionX2, positionY2);
+	m_options[m_numOptions].m_bSelected = bSelected;
+	m_options[m_numOptions].m_bRightJustify = bRightJustify;
+	return &m_options[m_numOptions++];
+}
+
+
+void
+CMenuMultiChoiceTwoLines::SetColors(const CRGBA &title, const CRGBA &normal, const CRGBA &selected)
+{
+	int i;
+	m_title.SetColor(title);
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].SetColors(normal, selected);
+}
+
+void
+CMenuMultiChoiceTwoLines::SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale)
+{
+	m_bSetTextScale = bTextScale;
+	m_textScale = newScale;
+	m_oldTextScale = oldScale;
+	m_bSetTitleTextScale = bTitleTextScale;
+}
+
+void
+CMenuMultiChoiceTwoLines::Draw(CRGBA const &optionHighlight ,CRGBA const &titleHighlight, float x, float y)
+{
+	int i;
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	if(m_cursor == -1)
+		m_title.Draw(m_position.x+x, m_position.y+y);
+	else
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	if(m_cursor == -1)
+		for(i = 0; i < m_numOptions; i++)
+			m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+	else
+		for(i = 0; i < m_numOptions; i++){
+			if(i == m_cursor)
+				m_options[i].Draw(optionHighlight, m_position.x+x, m_position.y+y);
+			else
+				m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+		}
+
+	if(m_bSetTextScale){
+		CFont::DrawFonts();
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+	}
+}
+
+void
+CMenuMultiChoiceTwoLines::DrawNormal(float x, float y)
+{
+	int i;
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	m_title.Draw(m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	for(i = 0; i < m_numOptions; i++)
+		m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+
+	if(m_bSetTextScale){
+		CFont::DrawFonts();
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+	}
+}
+
+void
+CMenuMultiChoiceTwoLines::DrawHighlighted(CRGBA const &titleHighlight, float x, float y)
+{
+	int i;
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	if(m_cursor == -1)
+		m_title.Draw(m_position.x+x, m_position.y+y);
+	else
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	for(i = 0; i < m_numOptions; i++)
+		m_options[i].Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+
+	if(m_bSetTextScale){
+		CFont::DrawFonts();
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+	}
+}
+
+void
+CMenuMultiChoiceTwoLines::SetAlpha(uint8 alpha)
+{
+	int i;
+	m_title.SetAlpha(alpha);
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].SetAlpha(alpha);
+}
+
+void
+CMenuMultiChoiceTwoLines::SetShadows(bool bDropShadows, CRGBA const &shadowColor, CVector2D const &shadowOffset)
+{
+	int i;
+	m_title.SetShadows(bDropShadows, shadowColor, shadowOffset);
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].SetShadows(bDropShadows, shadowColor, shadowOffset);
+}
+
+
+bool
+CMenuMultiChoiceTwoLines::GoNext(void)
+{
+	if(m_cursor == m_numOptions-1){
+		m_cursor = -1;
+		return false;
+	}else{
+		m_cursor++;
+		return true;
+	}
+}
+
+bool
+CMenuMultiChoiceTwoLines::GoPrev(void)
+{
+	if(m_cursor == 0){
+		m_cursor = -1;
+		return false;
+	}else{
+		m_cursor--;
+		return true;
+	}
+}
+
+void
+CMenuMultiChoiceTwoLines::SelectCurrentOptionUnderCursor(void)
+{
+	int i;
+	if(m_cursor == -1)
+		return;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].m_bSelected = false;
+	m_options[m_cursor].m_bSelected = true;
+}
+
+int
+CMenuMultiChoiceTwoLines::GetMenuSelection(void)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		if(m_options[i].m_bSelected)
+			return i;
+	return -1;
+}
+
+void
+CMenuMultiChoiceTwoLines::SetMenuSelection(int selection)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_options[i].m_bSelected = false;
+	m_options[selection%NUM_MULTICHOICE_OPTIONS].m_bSelected = true;
+}
+
+/*
+ * CMenuMultiChoiceTwoLinesTriggered
+ */
+
+void
+CMenuMultiChoiceTwoLinesTriggered::Initialise(void)
+{
+	int i;
+	for(i = 0; i < NUM_MULTICHOICE_OPTIONS; i++)
+		m_triggers[i] = nil;
+	m_defaultCancel = nil;
+}
+
+CPlaceableShOptionTwoLines*
+CMenuMultiChoiceTwoLinesTriggered::AddOption(wchar *text, float positionX, float positionY, Trigger trigger, bool bSelected, bool bRightJustify)
+{
+	CPlaceableShOptionTwoLines *option;
+	option = CMenuMultiChoiceTwoLines::AddOption(text, positionX, positionY, bSelected, bRightJustify);
+	if(option)
+		m_triggers[m_numOptions-1] = trigger;
+	return option;
+}
+
+CPlaceableShOptionTwoLines*
+CMenuMultiChoiceTwoLinesTriggered::AddOption(wchar *text1, float positionX1, float positionY1, wchar *text2, float positionX2, float positionY2, Trigger trigger, bool bSelected, bool bRightJustify)
+{
+	CPlaceableShOptionTwoLines *option;
+	option = CMenuMultiChoiceTwoLines::AddOption(text1, positionX1, positionY1, text2, positionX2, positionY2, bSelected, bRightJustify);
+	if(option)
+		m_triggers[m_numOptions-1] = trigger;
+	return option;
+}
+
+void
+CMenuMultiChoiceTwoLinesTriggered::SelectCurrentOptionUnderCursor(void)
+{
+	CMenuMultiChoiceTwoLines::SelectCurrentOptionUnderCursor();
+	if(m_cursor != -1)
+		m_triggers[m_cursor](this);
+}
+
+void
+CMenuMultiChoiceTwoLinesTriggered::SelectDefaultCancelAction(void)
+{
+	if(m_defaultCancel)
+		m_defaultCancel(this);
+}
+
+
+/*
+ * CMenuOnOff
+ */
+
+void
+CMenuOnOff::SetColors(const CRGBA &title, const CRGBA &options)
+{
+	m_title.SetColors(title, title);
+	m_options[0].SetColor(options);
+	m_options[1].SetColor(options);
+}
+
+void
+CMenuOnOff::SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale)
+{
+	m_bSetTextScale = bTextScale;
+	m_textScale = newScale;
+	m_oldTextScale = oldScale;
+	m_bSetTitleTextScale = bTitleTextScale;
+}
+
+void
+CMenuOnOff::SetOptionPosition(float x, float y, bool bRightJustify)
+{
+	m_options[0].SetPosition(x, y, bRightJustify);
+	m_options[1].SetPosition(x, y, bRightJustify);
+}
+
+void
+CMenuOnOff::AddTitle(wchar *text, bool bSelected, float positionX, float positionY, bool bRightJustify)
+{
+	m_title.m_text = text;
+	m_title.m_bSelected = bSelected;
+	m_title.SetPosition(positionX, positionY, bRightJustify);
+}
+
+void
+CMenuOnOff::Draw(CRGBA const &optionHighlight, CRGBA const &titleHighlight, float x, float y)
+{
+	if(m_type == 1){
+		m_options[0].m_text = TheText.Get("FEM_NO");
+		m_options[1].m_text = TheText.Get("FEM_YES");
+	}else if(m_type == 0){
+		m_options[0].m_text = TheText.Get("FEM_OFF");
+		m_options[1].m_text = TheText.Get("FEM_ON");
+	}
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	if(m_bActive)
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+	else
+		m_title.Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	if(m_bActive){
+		if(m_title.m_bSelected)
+			m_options[1].Draw(optionHighlight, m_position.x+x, m_position.y+y);
+		else
+			m_options[0].Draw(optionHighlight, m_position.x+x, m_position.y+y);
+	}else{
+		if(m_title.m_bSelected)
+			m_options[1].Draw(m_position.x+x, m_position.y+y);
+		else
+			m_options[0].Draw(m_position.x+x, m_position.y+y);
+	}
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+}
+
+void
+CMenuOnOff::DrawNormal(float x, float y)
+{
+	if(m_type == 1){
+		m_options[0].m_text = TheText.Get("FEM_NO");
+		m_options[1].m_text = TheText.Get("FEM_YES");
+	}else if(m_type == 0){
+		m_options[0].m_text = TheText.Get("FEM_OFF");
+		m_options[1].m_text = TheText.Get("FEM_ON");
+	}
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	m_title.Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	if(m_title.m_bSelected)
+		m_options[1].Draw(m_position.x+x, m_position.y+y);
+	else
+		m_options[0].Draw(m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+}
+
+void
+CMenuOnOff::DrawHighlighted(CRGBA const &titleHighlight, float x, float y)
+{
+	if(m_type == 1){
+		m_options[0].m_text = TheText.Get("FEM_NO");
+		m_options[1].m_text = TheText.Get("FEM_YES");
+	}else if(m_type == 0){
+		m_options[0].m_text = TheText.Get("FEM_OFF");
+		m_options[1].m_text = TheText.Get("FEM_ON");
+	}
+
+	if(m_bSetTextScale && m_bSetTitleTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+	if(m_bActive)
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+	else
+		m_title.Draw(CRGBA(0,0,0,0), m_position.x+x, m_position.y+y, false);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_textScale.x, m_textScale.y);
+
+	if(m_title.m_bSelected)
+		m_options[1].Draw(m_position.x+x, m_position.y+y);
+	else
+		m_options[0].Draw(m_position.x+x, m_position.y+y);
+
+	if(m_bSetTextScale)
+		CFont::SetScale(m_oldTextScale.x, m_oldTextScale.y);
+}
+
+void
+CMenuOnOff::SetAlpha(uint8 alpha)
+{
+	m_title.SetAlpha(alpha);
+	m_options[0].SetAlpha(alpha);
+	m_options[1].SetAlpha(alpha);
+}
+
+void
+CMenuOnOff::SetShadows(bool bDropShadows, CRGBA const &shadowColor, CVector2D const &shadowOffset)
+{
+	m_title.SetShadows(bDropShadows, shadowColor, shadowOffset);
+	m_options[0].SetShadows(bDropShadows, shadowColor, shadowOffset);
+	m_options[1].SetShadows(bDropShadows, shadowColor, shadowOffset);
+}
+
+/*
+ * CMenuOnOffTriggered
+ */
+
+void
+CMenuOnOffTriggered::SetOptionPosition(float x, float y, Trigger trigger, bool bRightJustify)
+{
+	CMenuOnOff::SetOptionPosition(x, y, bRightJustify);
+	if(trigger)
+		m_trigger = trigger;
+}
+
+void
+CMenuOnOffTriggered::SelectCurrentOptionUnderCursor(void)
+{
+	CMenuOnOff::SelectCurrentOptionUnderCursor();
+	if(m_trigger)
+		m_trigger(this);
+}
+
+
+
+/*
+ * CMenuSlider
+ */
+
+char CMenuSlider::Buf8[8];
+wchar CMenuSlider::Buf16[8];
+
+void
+CMenuSlider::SetColors(const CRGBA &title, const CRGBA &percentage, const CRGBA &left, const CRGBA &right)
+{
+	m_title.SetColor(title);
+	m_percentageText.SetColor(percentage);
+	m_colors[0] = left;
+	m_colors[1] = right;
+}
+
+
+void
+CMenuSlider::AddTickBox(float positionX, float positionY, float width, float heightLeft, float heightRight)
+{
+	m_box.SetPosition(positionX, positionY);
+	m_size[0].x = width;
+	m_size[0].y = heightLeft;
+	m_size[1].x = width;
+	m_size[1].y = heightRight;
+}
+
+void
+CMenuSlider::AddTitle(wchar *text, float positionX, float positionY)
+{
+	m_title.m_text = text;
+	m_title.SetPosition(positionX, positionY);
+}
+
+static CRGBA SELECTED_TEXT_COLOR_0(255, 182, 48, 255);
+
+void
+CMenuSlider::Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y)
+{
+	if(m_bActive){
+		CRGBA selectionCol = m_colors[0];
+		if(selectionCol.red == SELECTED_TEXT_COLOR_0.red &&
+		   selectionCol.green == SELECTED_TEXT_COLOR_0.green &&
+		   selectionCol.blue == SELECTED_TEXT_COLOR_0.blue &&
+		   selectionCol.alpha == SELECTED_TEXT_COLOR_0.alpha)
+			selectionCol = m_colors[1];
+
+		if(m_style == 1){
+			// solid bar
+			CRGBA shadowCol = m_box.GetShadowColor();
+			float f = m_value/1000.0f;
+			CVector2D boxPos = m_box.m_position + m_position + CVector2D(x,y);
+			if(m_box.m_bDropShadow)
+				CSprite2d::DrawRect(
+					CRect(boxPos.x + m_box.m_shadowOffset.x,
+					      boxPos.y + m_box.m_shadowOffset.y,
+					      boxPos.x + m_box.m_shadowOffset.x + m_size[0].x,
+					      boxPos.y + m_box.m_shadowOffset.y + m_size[0].y),
+					shadowCol);
+			CSprite2d::DrawRect(
+				CRect(boxPos.x, boxPos.y,
+				      boxPos.x + m_size[0].x, boxPos.y + m_size[0].y),
+				m_colors[1]);
+			CSprite2d::DrawRect(
+				CRect(boxPos.x, boxPos.y,
+				      boxPos.x + m_size[0].x*f, boxPos.y + m_size[0].y),
+				selectionCol);
+		}else if(m_style == 0){
+			// ticks...
+			CVector2D boxPos = m_box.m_position + m_position + CVector2D(x,y);
+			DrawTicks(boxPos, m_size[0], m_size[1].y,
+				m_value/1000.0f, m_colors[0], selectionCol, m_colors[1],
+				m_box.m_bDropShadow, m_box.m_shadowOffset, m_box.GetShadowColor());
+		}
+
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+
+		if(m_bDrawPercentage){
+			sprintf(Buf8, "%d%%", m_value/10);
+			AsciiToUnicode(Buf8, Buf16);
+			m_percentageText.m_text = Buf16;
+			m_percentageText.Draw(optionHighlight, m_position.x+x, m_position.y+y);
+		}
+	}else
+		CMenuSlider::DrawNormal(x, y);
+}
+
+void
+CMenuSlider::DrawNormal(float x, float y)
+{
+	if(m_style == 1){
+		// solid bar
+		CRGBA shadowCol = m_box.GetShadowColor();
+		float f = m_value/1000.0f;
+		CVector2D boxPos = m_box.m_position + m_position + CVector2D(x,y);
+		if(m_box.m_bDropShadow)
+			CSprite2d::DrawRect(
+				CRect(boxPos.x + m_box.m_shadowOffset.x,
+				      boxPos.y + m_box.m_shadowOffset.y,
+				      boxPos.x + m_box.m_shadowOffset.x + m_size[0].x,
+				      boxPos.y + m_box.m_shadowOffset.y + m_size[0].y),
+				shadowCol);
+		CSprite2d::DrawRect(
+			CRect(boxPos.x, boxPos.y,
+			      boxPos.x + m_size[0].x, boxPos.y + m_size[0].y),
+			m_colors[1]);
+		CSprite2d::DrawRect(
+			CRect(boxPos.x, boxPos.y,
+			      boxPos.x + m_size[0].x*f, boxPos.y + m_size[0].y),
+			m_colors[0]);
+	}else if(m_style == 0){
+		// ticks...
+		CVector2D boxPos = m_box.m_position + m_position + CVector2D(x,y);
+		DrawTicks(boxPos, m_size[0], m_size[1].y,
+			m_value/1000.0f, m_colors[0], m_colors[1],
+			m_box.m_bDropShadow, m_box.m_shadowOffset, m_box.GetShadowColor());
+	}
+
+	m_title.Draw(m_position.x+x, m_position.y+y);
+
+	if(m_bDrawPercentage){
+		sprintf(Buf8, "%d%%", m_value/10);
+		AsciiToUnicode(Buf8, Buf16);
+		m_percentageText.m_text = Buf16;
+		m_percentageText.Draw(m_percentageText.GetColor(), m_position.x+x, m_position.y+y);
+	}
+}
+
+void
+CMenuSlider::DrawHighlighted(const CRGBA &titleHighlight, float x, float y)
+{
+	if(m_bActive)
+		m_title.Draw(titleHighlight, m_position.x+x, m_position.y+y);
+	else
+		m_title.Draw(m_position.x+x, m_position.y+y);
+
+	if(m_style == 1){
+		// solid bar
+		CRGBA shadowCol = m_box.GetShadowColor();
+		float f = m_value/1000.0f;
+		CVector2D boxPos = m_box.m_position + m_position + CVector2D(x,y);
+		if(m_box.m_bDropShadow)
+			CSprite2d::DrawRect(
+				CRect(boxPos.x + m_box.m_shadowOffset.x,
+				      boxPos.y + m_box.m_shadowOffset.y,
+				      boxPos.x + m_box.m_shadowOffset.x + m_size[0].x,
+				      boxPos.y + m_box.m_shadowOffset.y + m_size[0].y),
+				shadowCol);
+		CSprite2d::DrawRect(
+			CRect(boxPos.x, boxPos.y,
+			      boxPos.x + m_size[0].x, boxPos.y + m_size[0].y),
+			m_colors[1]);
+		CSprite2d::DrawRect(
+			CRect(boxPos.x, boxPos.y,
+			      boxPos.x + m_size[0].x*f, boxPos.y + m_size[0].y),
+			m_colors[0]);
+	}else if(m_style == 0){
+		// ticks...
+		CVector2D boxPos = m_box.m_position + m_position + CVector2D(x,y);
+		DrawTicks(boxPos, m_size[0], m_size[1].y,
+			m_value/1000.0f, m_colors[0], m_colors[1],
+			m_box.m_bDropShadow, m_box.m_shadowOffset, m_box.GetShadowColor());
+	}
+
+	if(m_bDrawPercentage){
+		sprintf(Buf8, "%d%%", m_value/10);
+		AsciiToUnicode(Buf8, Buf16);
+		m_percentageText.m_text = Buf16;
+		m_percentageText.Draw(m_percentageText.GetColor(), m_position.x+x, m_position.y+y);
+	}
+}
+
+void
+CMenuSlider::DrawTicks(const CVector2D &position, const CVector2D &size, float heightRight, float level, const CRGBA &leftCol, const CRGBA &selCol, const CRGBA &rightCol, bool bShadow, const CVector2D &shadowOffset, const CRGBA &shadowColor)
+{
+	int i;
+	int numTicks = size.x / 8.0f;
+	float dy = heightRight - size.y;
+	float stepy = dy / numTicks;
+	int left = level*numTicks;
+	int drewSelection = 0;
+	for(i = 0; i < numTicks; i++){
+		CRect rect(position.x + 8.0f*i, position.y + dy - stepy*i,
+		           position.x + 8.0f*i + 4.0f, position.y + dy + size.y);
+		if(bShadow){
+			CRect shadowRect = rect;
+			shadowRect.left += shadowOffset.x;
+			shadowRect.right += shadowOffset.x;
+			shadowRect.top += shadowOffset.y;
+			shadowRect.bottom += shadowOffset.y;
+			CSprite2d::DrawRect(shadowRect, shadowColor);
+		}
+		if(i < left)
+			CSprite2d::DrawRect(rect, leftCol);
+		else if(!drewSelection){
+			CSprite2d::DrawRect(rect, selCol);
+			drewSelection = 1;
+		}else
+			CSprite2d::DrawRect(rect, rightCol);
+	}
+}
+
+void
+CMenuSlider::DrawTicks(const CVector2D &position, const CVector2D &size, float heightRight, float level, const CRGBA &leftCol, const CRGBA &rightCol, bool bShadow, const CVector2D &shadowOffset, const CRGBA &shadowColor)
+{
+	int i;
+	int numTicks = size.x / 8.0f;
+	float dy = heightRight - size.y;
+	float stepy = dy / numTicks;
+	int left = level*numTicks;
+	for(i = 0; i < numTicks; i++){
+		CRect rect(position.x + 8.0f*i, position.y + dy - stepy*i,
+		           position.x + 8.0f*i + 4.0f, position.y + dy + size.y);
+		if(bShadow){
+			CRect shadowRect = rect;
+			shadowRect.left += shadowOffset.x;
+			shadowRect.right += shadowOffset.x;
+			shadowRect.top += shadowOffset.y;
+			shadowRect.bottom += shadowOffset.y;
+			CSprite2d::DrawRect(shadowRect, shadowColor);
+		}
+		if(i < left)
+			CSprite2d::DrawRect(rect, leftCol);
+		else
+			CSprite2d::DrawRect(rect, rightCol);
+	}
+}
+
+void
+CMenuSlider::SetAlpha(uint8 alpha)
+{
+	m_title.SetAlpha(alpha);
+	m_box.SetAlpha(alpha);
+	m_someAlpha = alpha;
+	m_percentageText.SetAlpha(alpha);
+	m_colors[0].alpha = alpha;
+	m_colors[1].alpha = alpha;
+}
+
+void
+CMenuSlider::SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset)
+{
+	m_title.SetShadows(bDropShadows, shadowColor, shadowOffset);
+	m_box.SetShadows(bDropShadows, shadowColor, shadowOffset);
+	m_percentageText.SetShadows(bDropShadows, shadowColor, shadowOffset);
+}
+
+/*
+ * CMenuSliderTriggered
+ */
+	
+void
+CMenuSliderTriggered::AddTickBox(float positionX, float positionY, float width, float heightLeft, float heightRight, Trigger trigger, Trigger alwaysTrigger)
+{
+	CMenuSlider::AddTickBox(positionX, positionY, width, heightLeft, heightRight);
+	m_trigger = trigger;
+	m_alwaysTrigger = alwaysTrigger;
+}
+
+void
+CMenuSliderTriggered::Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y)
+{
+	CMenuSlider::Draw(optionHighlight, titleHighlight, x, y);
+	if(m_alwaysTrigger)
+		m_alwaysTrigger(this);
+}
+
+bool
+CMenuSliderTriggered::GoLeft(void)
+{
+	CMenuSlider::GoLeft();
+	if(m_trigger)
+		m_trigger(this);
+	return true;
+}
+
+bool
+CMenuSliderTriggered::GoRight(void)
+{
+	CMenuSlider::GoRight();
+	if(m_trigger)
+		m_trigger(this);
+	return true;
+}
+
+bool
+CMenuSliderTriggered::GoLeftStill(void)
+{
+	CMenuSlider::GoLeftStill();
+	if(m_trigger)
+		m_trigger(this);
+	return true;
+}
+
+bool
+CMenuSliderTriggered::GoRightStill(void)
+{
+	CMenuSlider::GoRightStill();
+	if(m_trigger)
+		m_trigger(this);
+	return true;
+}
+
+/*
+ * CMenuLineLister
+ */
+
+CMenuLineLister::CMenuLineLister(void)
+ : m_numLines(0), m_width(0.0f), m_height(0.0f),
+   m_scrollPosition(0.0f), m_scrollSpeed(1.0f), m_lineSpacing(15.0f), field_10E8(0)
+{
+	int i;
+	for(i = 0; i < NUM_LINELISTER_LINES_TOTAL; i++){
+		m_lineAlphas[i] = 0;
+		m_lineFade[i] = 0;
+	}
+}
+
+
+void
+CMenuLineLister::SetLinesColor(const CRGBA &color)
+{
+	int i;
+	for(i = 0; i < NUM_LINELISTER_LINES_TOTAL; i++){
+		m_linesLeft[i].SetColor(color);
+		m_linesRight[i].SetColor(color);
+	}
+}
+
+void
+CMenuLineLister::ResetNumberOfTextLines(void)
+{
+	int i;
+	m_numLines = 0;
+	for(i = 0; i < NUM_LINELISTER_LINES_TOTAL; i++){
+		m_lineAlphas[i] = 0;
+		m_lineFade[i] = 0;
+	}
+	for(i = 0; i < NUM_LINELISTER_LINES_TOTAL; i++){
+		// note this doesn't clear lines 0-14, probably an oversight
+		GetLeftLine(i)->m_text = nil;
+		GetRightLine(i)->m_text = nil;
+	}
+}
+
+bool
+CMenuLineLister::AddTextLine(wchar *left, wchar *right)
+{
+	CPlaceableShText *leftLine, *rightLine;
+	if(m_numLines == NUM_LINELISTER_LINES)
+		return false;
+	leftLine = GetLeftLine(m_numLines);
+	leftLine->m_text = left;
+	leftLine->SetPosition(0.0f, m_lineSpacing*(m_numLines+15));
+	rightLine = GetRightLine(m_numLines);
+	rightLine->m_text = right;
+	rightLine->SetPosition(leftLine->m_position.x, leftLine->m_position.y);
+	m_numLines++;
+	return true;
+}
+
+void
+CMenuLineLister::Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y)
+{
+	int i, n;
+
+	m_scrollPosition += m_scrollSpeed;
+	n = m_numLines + 15;
+	if(m_scrollSpeed > 0.0f){
+		if(m_scrollPosition > n*m_lineSpacing)
+			m_scrollPosition = 0.0f;
+	}else{
+		if(m_scrollPosition < 0.0f)
+			m_scrollPosition = n*m_lineSpacing;
+	}
+	// this is a weird condition....
+	for(i = 0;
+	    m_scrollPosition < i*m_lineSpacing || m_scrollPosition >= (i+1)*m_lineSpacing;
+	    i++);
+
+	float screenPos = 0.0f;
+	for(; i < n; i++){
+		CVector2D linePos = m_linesLeft[i].m_position;
+
+		if(linePos.y+m_position.y - (m_scrollPosition+m_position.y) < 64.0f)
+			m_lineFade[i] = -4.0f*Abs(m_scrollSpeed);
+		else
+			m_lineFade[i] = 4.0f*Abs(m_scrollSpeed);
+		int newAlpha = m_lineAlphas[i] + m_lineFade[i];
+		if(newAlpha < 0) newAlpha = 0;
+		if(newAlpha > 255) newAlpha = 255;
+		m_lineAlphas[i] = newAlpha;
+
+		uint8 alpha = m_linesLeft[i].m_shadowColor.alpha;
+
+		// apply alpha
+		m_linesLeft[i].SetAlpha((alpha*m_lineAlphas[i])>>8);
+		m_linesRight[i].SetAlpha((alpha*m_lineAlphas[i])>>8);
+
+		m_linesLeft[i].Draw(m_position.x+x, m_position.y+y - m_scrollPosition);
+		CFont::SetRightJustifyOn();
+		m_linesRight[i].Draw(m_position.x+x + m_width, m_position.y+y - m_scrollPosition);
+		CFont::SetRightJustifyOff();
+
+		// restore alpha
+		m_linesLeft[i].SetAlpha(alpha);
+		m_linesRight[i].SetAlpha(alpha);
+
+		screenPos += m_lineSpacing;
+		if(screenPos >= m_height)
+			break;
+	}
+
+	m_scrollSpeed = 1.0f;
+}
+
+void
+CMenuLineLister::SetAlpha(uint8 alpha)
+{
+	int i;
+	for(i = 0; i < NUM_LINELISTER_LINES_TOTAL; i++){
+		m_linesLeft[i].SetAlpha(alpha);
+		m_linesRight[i].SetAlpha(alpha);
+	}
+}
+
+void
+CMenuLineLister::SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset)
+{
+	int i;
+	for(i = 0; i < NUM_LINELISTER_LINES_TOTAL; i++){
+		m_linesLeft[i].SetShadows(bDropShadows, shadowColor, shadowOffset);
+		m_linesRight[i].SetShadows(bDropShadows, shadowColor, shadowOffset);
+	}
+}
+
+
+/*
+ * CMenuPage
+ */
+
+void
+CMenuPage::Initialise(void)
+{
+	int i;
+	m_numControls = 0;
+	m_pCurrentControl = nil;
+	m_cursor = 0;
+	for(i = 0; i < NUM_PAGE_WIDGETS; i++)
+		m_controls[i] = nil;
+}
+
+bool
+CMenuPage::AddMenu(CMenuBase *widget)
+{
+	if(m_numControls >= NUM_PAGE_WIDGETS)
+		return false;
+	m_controls[m_numControls] = widget;
+	if(m_numControls == 0){
+		m_pCurrentControl = widget;
+		m_cursor = 0;
+	}
+	m_numControls++;
+	return true;
+}
+
+bool
+CMenuPage::IsActiveMenuTwoState(void)
+{
+	return m_pCurrentControl && m_pCurrentControl->m_bTwoState;
+}
+
+void
+CMenuPage::ActiveMenuTwoState_SelectNextPosition(void)
+{
+	int sel;
+	if(m_pCurrentControl == nil || !m_pCurrentControl->m_bTwoState)
+		return;
+	m_pCurrentControl->GoFirst();
+	sel = m_pCurrentControl->GetMenuSelection();
+	if(sel == 1)
+		m_pCurrentControl->SelectCurrentOptionUnderCursor();
+	else if(sel == 0){
+		m_pCurrentControl->GoNext();
+		m_pCurrentControl->SelectCurrentOptionUnderCursor();
+	}
+}
+
+void
+CMenuPage::Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y)
+{
+	int i;
+	for(i = 0; i < m_numControls; i++)
+		if(m_controls[i]){
+			if(i == m_cursor)
+				m_controls[i]->Draw(optionHighlight, titleHighlight, x, y);
+			else
+				m_controls[i]->DrawNormal(x, y);
+		}
+}
+
+void
+CMenuPage::DrawHighlighted(const CRGBA &titleHighlight, float x, float y)
+{
+	int i;
+	for(i = 0; i< m_numControls; i++)
+		if(m_controls[i]){
+			if(i == m_cursor)
+				m_controls[i]->DrawHighlighted(titleHighlight, x, y);
+			else
+				m_controls[i]->DrawNormal(x, y);
+		}
+}
+
+void
+CMenuPage::DrawNormal(float x, float y)
+{
+	int i;
+	for(i = 0; i< m_numControls; i++)
+		if(m_controls[i])
+			m_controls[i]->DrawNormal(x, y);
+}
+
+void
+CMenuPage::ActivatePage(void)
+{
+	m_cursor = 0;
+	if(m_numControls == 0)
+		return;
+	for(;;){
+		m_pCurrentControl = m_controls[m_cursor];
+		if(m_pCurrentControl->GoFirst())
+			return;
+		if(m_cursor == m_numControls-1)
+			m_cursor = 0;
+		else
+			m_cursor++;
+	}
+}
+
+void
+CMenuPage::SetAlpha(uint8 alpha)
+{
+	int i;
+	for(i = 0; i< m_numControls; i++)
+		if(m_controls[i])
+			m_controls[i]->SetAlpha(alpha);
+}
+
+void
+CMenuPage::SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset)
+{
+	int i;
+	for(i = 0; i< m_numControls; i++)
+		if(m_controls[i])
+			m_controls[i]->SetShadows(bDropShadows, shadowColor, shadowOffset);
+}
+
+void
+CMenuPage::GoUpMenuOnPage(void)
+{
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	do{
+		if(m_cursor == 0)
+			m_cursor = m_numControls-1;
+		else
+			m_cursor--;
+		m_pCurrentControl = m_controls[m_cursor];
+	}while(!m_pCurrentControl->GoLast());
+}
+
+void
+CMenuPage::GoDownMenuOnPage(void)
+{
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	do{
+		if(m_cursor == m_numControls-1)
+			m_cursor = 0;
+		else
+			m_cursor++;
+		m_pCurrentControl = m_controls[m_cursor];
+	}while(!m_pCurrentControl->GoFirst());
+}
+
+void
+CMenuPage::GoLeftMenuOnPage(void)
+{
+	// same as up
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	do{
+		if(m_cursor == 0)
+			m_cursor = m_numControls-1;
+		else
+			m_cursor--;
+		m_pCurrentControl = m_controls[m_cursor];
+	}while(!m_pCurrentControl->GoLast());
+}
+
+void
+CMenuPage::GoRightMenuOnPage(void)
+{
+	// same as right
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	do{
+		if(m_cursor == m_numControls-1)
+			m_cursor = 0;
+		else
+			m_cursor++;
+		m_pCurrentControl = m_controls[m_cursor];
+	}while(!m_pCurrentControl->GoFirst());
+}
+
+/*
+ * CMenuPageAnyMove
+ */
+
+void
+CMenuPageAnyMove::Initialise(void)
+{
+	int i;
+	CMenuPage::Initialise();
+	for(i = 0; i < NUM_PAGE_WIDGETS; i++){
+		m_moveTab[i].left = -1;
+		m_moveTab[i].right = -1;
+		m_moveTab[i].up = -1;
+		m_moveTab[i].down = -1;
+	}
+}
+
+bool
+CMenuPageAnyMove::AddMenu(CMenuBase *widget, FEC_MOVETAB *moveTab)
+{
+	if(AddMenu(widget)){
+		m_moveTab[m_numControls-1] = *moveTab;
+		return true;
+	}
+	return false;
+}
+
+void
+CMenuPageAnyMove::GoUpMenuOnPage(void)
+{
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	int move = m_moveTab[m_cursor].up;
+	if(move == -1)
+		CMenuPage::GoUpMenuOnPage();
+	else{	// BUG: no else in original code
+		m_cursor = move;
+		m_pCurrentControl = m_controls[m_cursor];
+		m_pCurrentControl->GoLast();
+	}
+}
+
+void
+CMenuPageAnyMove::GoDownMenuOnPage(void)
+{
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	int move = m_moveTab[m_cursor].down;
+	if(move == -1)
+		CMenuPage::GoDownMenuOnPage();
+	else{	// BUG: no else in original code
+		m_cursor = move;
+		m_pCurrentControl = m_controls[m_cursor];
+		m_pCurrentControl->GoLast();
+	}
+}
+
+void
+CMenuPageAnyMove::GoLeftMenuOnPage(void)
+{
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	int move = m_moveTab[m_cursor].left;
+	if(move == -1)
+		CMenuPage::GoLeftMenuOnPage();
+	else{	// BUG: no else in original code
+		m_cursor = move;
+		m_pCurrentControl = m_controls[m_cursor];
+		m_pCurrentControl->GoLast();
+	}
+}
+
+void
+CMenuPageAnyMove::GoRightMenuOnPage(void)
+{
+	if(m_pCurrentControl == nil)
+		return;
+	m_pCurrentControl->DeactivateMenu();
+	int move = m_moveTab[m_cursor].right;
+	if(move == -1)
+		CMenuPage::GoRightMenuOnPage();
+	else{	// BUG: no else in original code
+		m_cursor = move;
+		m_pCurrentControl = m_controls[m_cursor];
+		m_pCurrentControl->GoLast();
+	}
+}
diff --git a/src/core/FrontEndControls.h b/src/core/FrontEndControls.h
new file mode 100644
index 00000000..5b6f95bb
--- /dev/null
+++ b/src/core/FrontEndControls.h
@@ -0,0 +1,712 @@
+#pragma once
+
+enum {
+	NUM_MULTICHOICE_OPTIONS = 16,
+	// 50 actual lines and 15 for spacing
+	NUM_LINELISTER_LINES = 50,
+	NUM_LINELISTER_LINES_TOTAL = NUM_LINELISTER_LINES + 15,
+	NUM_PAGE_WIDGETS = 10,
+};
+
+
+class CPlaceableText
+{
+public:
+	CVector2D m_position;
+	CRGBA m_color;
+	wchar *m_text;
+
+	CPlaceableText(void)
+	 : m_position(0.0f, 0.0f), m_color(255, 255, 255, 255) {}
+	void SetPosition(float x, float y) { m_position.x = x; m_position.y = y; }
+	void SetColor(const CRGBA &color) { m_color = color; }
+	CRGBA GetColor(void) { return m_color; }
+	void SetAlpha(uint8 alpha) { m_color.alpha = alpha; }
+};
+
+// No trace of this in the game but it makes the other classes simpler
+class CPlaceableTextTwoLines
+{
+public:
+	CPlaceableText m_line1;
+	CPlaceableText m_line2;
+
+	void SetColor(const CRGBA &color) { m_line1.SetColor(color); m_line2.SetColor(color); }
+	void SetAlpha(uint8 alpha) { m_line1.SetAlpha(alpha); m_line2.SetAlpha(alpha); }
+};
+
+// No trace of this in the game but it makes the other classes simpler
+class CShadowInfo
+{
+public:
+	bool m_bRightJustify;
+	bool m_bDropShadow;
+	CRGBA m_shadowColor;
+	CVector2D m_shadowOffset;
+
+	CShadowInfo(void)
+	 : m_bRightJustify(false), m_bDropShadow(false),
+	   m_shadowColor(255, 255, 255, 255),
+	   m_shadowOffset(-1.0f, -1.0f) {}
+	CRGBA GetShadowColor(void) { return m_shadowColor; }
+	void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset){
+		m_bDropShadow = bDropShadows;
+		m_shadowColor = shadowColor;
+		m_shadowOffset = shadowOffset;
+	}
+};
+
+// No trace of this in the game but it makes the other classes simpler
+class CSelectable
+{
+public:
+	bool m_bSelected;
+	CRGBA m_selectedColor;
+
+	CSelectable(void) : m_bSelected(false) {}
+	CRGBA GetSelectedColor(void) { return m_selectedColor; }
+};
+
+class CPlaceableShText : public CPlaceableText, public CShadowInfo
+{
+public:
+	using CPlaceableText::SetPosition;
+	void SetPosition(float x, float y, bool bRightJustify) { SetPosition(x, y); m_bRightJustify = bRightJustify; }
+	void SetAlpha(uint8 alpha)  { m_shadowColor.alpha = alpha; CPlaceableText::SetAlpha(alpha); }
+
+	void Draw(float x, float y);
+	void Draw(const CRGBA &color, float x, float y);
+	// unused arguments it seems
+	void DrawShWrap(float x, float y, float wrapX, float wrapY) { Draw(x, y); }
+};
+
+class CPlaceableShTextTwoLines : public CPlaceableTextTwoLines, public CShadowInfo
+{
+public:
+	void SetAlpha(uint8 alpha)  { m_shadowColor.alpha = alpha; CPlaceableTextTwoLines::SetAlpha(alpha); }
+
+	void Draw(float x, float y);
+	void Draw(const CRGBA &color, float x, float y);
+};
+
+class CPlaceableShOption : public CPlaceableShText, public CSelectable
+{
+public:
+	void SetColors(const CRGBA &normal, const CRGBA &selection) { CPlaceableShText::SetColor(normal); m_selectedColor = selection; }
+	void SetAlpha(uint8 alpha)  { m_selectedColor.alpha = alpha; CPlaceableShText::SetAlpha(alpha); }
+
+	using CPlaceableShText::Draw;
+	void Draw(const CRGBA &highlightColor, float x, float y, bool bHighlight);
+};
+
+class CPlaceableShOptionTwoLines : public CPlaceableShTextTwoLines, public CSelectable
+{
+public:
+	void SetColors(const CRGBA &normal, const CRGBA &selection) { CPlaceableShTextTwoLines::SetColor(normal); m_selectedColor = selection; }
+	void SetAlpha(uint8 alpha)  { m_selectedColor.alpha = alpha; CPlaceableShTextTwoLines::SetAlpha(alpha); }
+
+	using CPlaceableShTextTwoLines::Draw;
+	void Draw(const CRGBA &highlightColor, float x, float y, bool bHighlight);
+};
+
+class CPlaceableSprite
+{
+public:
+	CSprite2d *m_pSprite;
+	CVector2D m_position;
+	CVector2D m_size;
+	CRGBA m_color;
+
+	CPlaceableSprite(void)
+	 : m_pSprite(nil), m_position(0.0f, 0.0f),
+	   m_size(0.0f, 0.0f), m_color(255, 255, 255, 255) {}
+
+	void SetPosition(float x, float y) { m_position.x = x; m_position.y = y; }
+	void SetAlpha(uint8 alpha) { m_color.alpha = alpha; }
+
+	void Draw(float x, float y);
+	void Draw(const CRGBA &color, float x, float y);
+};
+
+class CPlaceableShSprite
+{
+public:
+	CPlaceableSprite m_sprite;
+	CPlaceableSprite m_shadow;
+	bool m_bDropShadow;
+
+	CPlaceableShSprite(void) : m_bDropShadow(false) {}
+
+	void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset){
+		m_bDropShadow = bDropShadows;
+		m_shadow.m_color = shadowColor;
+		m_shadow.m_position = shadowOffset;
+	}
+	void SetAlpha(uint8 alpha)  { m_sprite.SetAlpha(alpha); m_shadow.SetAlpha(alpha); }
+
+	void Draw(float x, float y);
+};
+
+
+class CMenuBase
+{
+public:
+	CVector2D m_position;
+	bool m_bTwoState;
+
+	CMenuBase(void)
+	 : m_position(0.0f, 0.0f), m_bTwoState(false) {}
+	void SetPosition(float x, float y) { m_position.x = x; m_position.y = y; }
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y) = 0;
+	virtual void DrawNormal(float x, float y) = 0;
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y) = 0;
+	virtual void SetAlpha(uint8 alpha) = 0;
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset) = 0;
+	virtual bool GoNext(void) = 0;
+	virtual bool GoPrev(void) = 0;
+	virtual bool GoDown(void) = 0;
+	virtual bool GoUp(void) = 0;
+	virtual bool GoDownStill(void) = 0;
+	virtual bool GoUpStill(void) = 0;
+	virtual bool GoLeft(void) = 0;
+	virtual bool GoRight(void) = 0;
+	virtual bool GoLeftStill(void) = 0;
+	virtual bool GoRightStill(void) = 0;
+	virtual bool GoFirst(void) = 0;
+	virtual bool GoLast(void) = 0;
+	virtual void SelectCurrentOptionUnderCursor(void) = 0;
+	virtual void SelectDefaultCancelAction(void) = 0;
+	virtual void ActivateMenu(bool first) = 0;
+	virtual void DeactivateMenu(void) = 0;
+	virtual int GetMenuSelection(void) = 0;
+	virtual void SetMenuSelection(int selection) = 0;
+};
+
+class CMenuDummy : public CMenuBase
+{
+public:
+	bool m_bActive;
+
+	virtual void Draw(const CRGBA &, const CRGBA &, float x, float y) {}
+	virtual void DrawNormal(float x, float y) {}
+	virtual void DrawHighlighted(const CRGBA &, float x, float y) {}
+	virtual void SetAlpha(uint8 alpha) {}
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset) {}
+	virtual bool GoNext(void) { DeactivateMenu(); return false; }
+	virtual bool GoPrev(void) { DeactivateMenu(); return false; }
+	virtual bool GoDown(void) { return GoNext(); }
+	virtual bool GoUp(void) { return GoPrev(); }
+	virtual bool GoDownStill(void) { return false; }
+	virtual bool GoUpStill(void) { return false; }
+	virtual bool GoLeft(void) { return true; }
+	virtual bool GoRight(void) { return true; }
+	virtual bool GoLeftStill(void) { return true; }
+	virtual bool GoRightStill(void) { return true; }
+	virtual bool GoFirst(void) { ActivateMenu(true); return true; }
+	virtual bool GoLast(void) { ActivateMenu(true); return true; }
+	virtual void SelectCurrentOptionUnderCursor(void) {}
+	virtual void SelectDefaultCancelAction(void) {}
+	virtual void ActivateMenu(bool first) { m_bActive = true; }
+	virtual void DeactivateMenu(void) { m_bActive = false; }
+	virtual int GetMenuSelection(void) { return -1; }
+	virtual void SetMenuSelection(int) {}
+};
+
+class CMenuPictureAndText : public CMenuBase
+{
+public:
+	int m_numSprites;
+	CPlaceableShSprite m_sprites[5];
+	int m_numTexts;
+	CPlaceableShText m_texts[20];
+
+	CVector2D m_oldTextScale;
+	CVector2D m_textScale;
+	bool m_bSetTextScale;
+
+	float m_wrapX;
+	float m_oldWrapx;
+	bool m_bWrap;
+	// missing some?
+
+
+	CMenuPictureAndText(void)
+	 : m_numSprites(0), m_numTexts(0),
+	   m_bSetTextScale(false), m_bWrap(false) {}
+
+	void SetNewOldShadowWrapX(bool bWrapX, float newWrapX, float oldWrapX);
+	void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale);
+	void SetTextsColor(const CRGBA &color);
+	void AddText(wchar *text, float positionX, float positionY, const CRGBA &color, bool bRightJustify);
+	void AddPicture(CSprite2d *sprite, CSprite2d *shadow, float positionX, float positionY, float width, float height, const CRGBA &color);
+	void AddPicture(CSprite2d *sprite, float positionX, float positionY, float width, float height, const CRGBA &color);
+
+	virtual void Draw(const CRGBA &, const CRGBA &, float x, float y);
+	virtual void DrawNormal(float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
+	virtual void DrawHighlighted(const CRGBA &, float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
+	virtual void SetAlpha(uint8 alpha);
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
+	virtual bool GoNext(void) { return false; }
+	virtual bool GoPrev(void) { return false; }
+	virtual bool GoDown(void) { return GoNext(); }
+	virtual bool GoUp(void) { return GoPrev(); }
+	virtual bool GoDownStill(void) { return false; }
+	virtual bool GoUpStill(void) { return false; }
+	virtual bool GoLeft(void) { return true; }
+	virtual bool GoRight(void) { return true; }
+	virtual bool GoLeftStill(void) { return true; }
+	virtual bool GoRightStill(void) { return true; }
+	virtual bool GoFirst(void) { return false; }
+	virtual bool GoLast(void) { return false; }
+	virtual void SelectCurrentOptionUnderCursor(void) {}
+	virtual void SelectDefaultCancelAction(void) {}
+	virtual void ActivateMenu(bool first) {}
+	virtual void DeactivateMenu(void) {}
+	virtual int GetMenuSelection(void) { return -1; }
+	virtual void SetMenuSelection(int) {}
+};
+
+class CMenuMultiChoice : public CMenuBase
+{
+public:
+	int m_numOptions;
+	CPlaceableShText m_title;
+	CPlaceableShOption m_options[NUM_MULTICHOICE_OPTIONS];
+	int m_cursor;
+	CVector2D m_oldTextScale;
+	CVector2D m_textScale;
+	bool m_bSetTextScale;
+	bool m_bSetTitleTextScale;
+
+	CMenuMultiChoice(void)
+	 : m_numOptions(0), m_cursor(-1),
+	   m_bSetTextScale(false), m_bSetTitleTextScale(false) {}
+
+	void AddTitle(wchar *text, float positionX, float positionY, bool bRightJustify);
+	CPlaceableShOption *AddOption(wchar *text, float positionX, float positionY, bool bSelected, bool bRightJustify);
+	void SetColors(const CRGBA &title, const CRGBA &normal, const CRGBA &selected);
+	void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale);
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual void DrawNormal(float x, float y);
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
+	virtual void SetAlpha(uint8 alpha);
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
+	virtual bool GoNext(void);
+	virtual bool GoPrev(void);
+	virtual bool GoDown(void) { return GoNext(); }
+	virtual bool GoUp(void) { return GoPrev(); }
+	virtual bool GoDownStill(void) { return false; }
+	virtual bool GoUpStill(void) { return false; }
+	virtual bool GoLeft(void) { return GoPrev(); }
+	virtual bool GoRight(void) { return GoNext(); }
+	virtual bool GoLeftStill(void) { return true; }
+	virtual bool GoRightStill(void) { return true; }
+	virtual bool GoFirst(void) { m_cursor = 0; return true; }
+	virtual bool GoLast(void) { m_cursor = m_numOptions-1; return true; }
+	virtual void SelectCurrentOptionUnderCursor(void);
+	virtual void SelectDefaultCancelAction(void) {}
+	virtual void ActivateMenu(bool first) { m_cursor = first ? 0 : m_numOptions-1; }
+	virtual void DeactivateMenu(void) { m_cursor = -1; }
+	virtual int GetMenuSelection(void);
+	virtual void SetMenuSelection(int selection);
+};
+
+class CMenuMultiChoiceTriggered : public CMenuMultiChoice
+{
+public:
+	typedef void (*Trigger)(CMenuMultiChoiceTriggered *);
+
+	Trigger m_triggers[NUM_MULTICHOICE_OPTIONS];
+	Trigger m_defaultCancel;
+
+	CMenuMultiChoiceTriggered(void) { Initialise(); }
+
+	void Initialise(void);
+	CPlaceableShOption *AddOption(wchar *text, float positionX, float positionY, Trigger trigger, bool bSelected, bool bRightJustify);
+
+	virtual void SelectCurrentOptionUnderCursor(void);
+	virtual void SelectDefaultCancelAction(void);
+};
+
+class CMenuMultiChoiceTriggeredAlways : public CMenuMultiChoiceTriggered
+{
+public:
+	Trigger m_alwaysNormalTrigger;
+	Trigger m_alwaysHighlightTrigger;
+	Trigger m_alwaysTrigger;
+
+	CMenuMultiChoiceTriggeredAlways(void)
+	 : m_alwaysNormalTrigger(nil), m_alwaysHighlightTrigger(nil), m_alwaysTrigger(nil) {}
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual void DrawNormal(float x, float y);
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
+};
+
+class CMenuMultiChoicePictured : public CMenuMultiChoice
+{
+public:
+	CPlaceableSprite m_sprites[NUM_MULTICHOICE_OPTIONS];
+	bool m_bHasSprite[NUM_MULTICHOICE_OPTIONS];
+
+	CMenuMultiChoicePictured(void) { Initialise(); }
+	void Initialise(void);
+	using CMenuMultiChoice::AddOption;
+	CPlaceableShOption *AddOption(CSprite2d *sprite, float positionX, float positionY, const CVector2D &size, bool bSelected);
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual void DrawNormal(float x, float y);
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
+	virtual void SetAlpha(uint8 alpha);
+	// unnecessary - same as base class
+//	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
+};
+
+class CMenuMultiChoicePicturedTriggered : public CMenuMultiChoicePictured
+{
+public:
+	typedef void (*Trigger)(CMenuMultiChoicePicturedTriggered *);
+
+	Trigger m_triggers[NUM_MULTICHOICE_OPTIONS];
+	Trigger m_defaultCancel;
+
+	CMenuMultiChoicePicturedTriggered(void) { Initialise(); }
+
+	void Initialise(void);
+	using CMenuMultiChoicePictured::AddOption;
+	CPlaceableShOption *AddOption(CSprite2d *sprite, float positionX, float positionY, const CVector2D &size, Trigger trigger, bool bSelected);
+
+	virtual void SelectCurrentOptionUnderCursor(void);
+	virtual void SelectDefaultCancelAction(void);
+};
+
+struct FEC_MOVETAB
+{
+	int8 right;
+	int8 left;
+	int8 down;
+	int8 up;
+};
+
+class CMenuMultiChoicePicturedTriggeredAnyMove : public CMenuMultiChoicePicturedTriggered
+{
+public:
+	FEC_MOVETAB m_moveTab[NUM_MULTICHOICE_OPTIONS];
+
+	CMenuMultiChoicePicturedTriggeredAnyMove(void) { Initialise(); }
+
+	void Initialise(void);
+	using CMenuMultiChoicePicturedTriggered::AddOption;
+	CPlaceableShOption *AddOption(CSprite2d *sprite, FEC_MOVETAB *moveTab, float positionX, float positionY, const CVector2D &size, Trigger trigger, bool bSelected);
+
+	virtual bool GoDown(void);
+	virtual bool GoUp(void);
+	virtual bool GoLeft(void);
+	virtual bool GoRight(void);
+};
+
+// copy of CMenuMultiChoice pretty much except for m_options type
+class CMenuMultiChoiceTwoLines : public CMenuBase
+{
+public:
+	int m_numOptions;
+	CPlaceableShText m_title;
+	CPlaceableShOptionTwoLines m_options[NUM_MULTICHOICE_OPTIONS];
+	int m_cursor;
+	CVector2D m_oldTextScale;
+	CVector2D m_textScale;
+	bool m_bSetTextScale;
+	bool m_bSetTitleTextScale;
+
+	CMenuMultiChoiceTwoLines(void)
+	 : m_numOptions(0), m_cursor(-1),
+	   m_bSetTextScale(false), m_bSetTitleTextScale(false) {}
+
+	void AddTitle(wchar *text, float positionX, float positionY, bool bRightJustify);
+	CPlaceableShOptionTwoLines *AddOption(wchar *text, float positionX, float positionY, bool bSelected, bool bRightJustify);
+	CPlaceableShOptionTwoLines *AddOption(wchar *text1, float positionX1, float positionY1, wchar *text2, float positionX2, float positionY2, bool bSelected, bool bRightJustify);
+	void SetColors(const CRGBA &title, const CRGBA &normal, const CRGBA &selected);
+	void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale);
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual void DrawNormal(float x, float y);
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
+	virtual void SetAlpha(uint8 alpha);
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
+	virtual bool GoNext(void);
+	virtual bool GoPrev(void);
+	virtual bool GoDown(void) { return GoNext(); }
+	virtual bool GoUp(void) { return GoPrev(); }
+	virtual bool GoDownStill(void) { return true; }
+	virtual bool GoUpStill(void) { return true; }
+	virtual bool GoLeft(void) { return GoPrev(); }
+	virtual bool GoRight(void) { return GoNext(); }
+	virtual bool GoLeftStill(void) { return true; }
+	virtual bool GoRightStill(void) { return true; }
+	virtual bool GoFirst(void) { m_cursor = 0; return true; }
+	virtual bool GoLast(void) { m_cursor = m_numOptions-1; return true; }
+	virtual void SelectCurrentOptionUnderCursor(void);
+	virtual void SelectDefaultCancelAction(void) {}
+	virtual void ActivateMenu(bool first) { m_cursor = first ? 0 : m_numOptions-1; }
+	virtual void DeactivateMenu(void) { m_cursor = -1; }
+	virtual int GetMenuSelection(void);
+	virtual void SetMenuSelection(int selection);
+};
+
+// copy of CMenuMultiChoiceTriggered except for m_options
+class CMenuMultiChoiceTwoLinesTriggered : public CMenuMultiChoiceTwoLines
+{
+public:
+	typedef void (*Trigger)(CMenuMultiChoiceTwoLinesTriggered *);
+
+	Trigger m_triggers[NUM_MULTICHOICE_OPTIONS];
+	Trigger m_defaultCancel;
+
+	CMenuMultiChoiceTwoLinesTriggered(void) { Initialise(); }
+
+	void Initialise(void);
+	CPlaceableShOptionTwoLines *AddOption(wchar *text, float positionX, float positionY, Trigger trigger, bool bSelected, bool bRightJustify);
+	CPlaceableShOptionTwoLines *AddOption(wchar *text1, float positionX1, float positionY1, wchar *text2, float positionX2, float positionY2, Trigger trigger, bool bSelected, bool bRightJustify);
+
+	virtual void SelectCurrentOptionUnderCursor(void);
+	virtual void SelectDefaultCancelAction(void);
+};
+
+
+class CMenuOnOff : public CMenuBase
+{
+public:
+	CPlaceableShOption m_title;
+	CPlaceableShText m_options[2];
+	bool m_bActive;
+	bool m_bSetTextScale;
+	bool m_bSetTitleTextScale;
+	CVector2D m_textScale;
+	CVector2D m_oldTextScale;
+	int m_type;	// 0: on/off 1: yes/no
+
+	void SetColors(const CRGBA &title, const CRGBA &options);
+	void SetNewOldTextScale(bool bTextScale, const CVector2D &newScale, const CVector2D &oldScale, bool bTitleTextScale);
+	void SetOptionPosition(float x, float y, bool bRightJustify);
+	void AddTitle(wchar *text, bool bSelected, float positionX, float positionY, bool bRightJustify);
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual void DrawNormal(float x, float y);
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
+	virtual void SetAlpha(uint8 alpha);
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
+	virtual bool GoNext(void) { DeactivateMenu(); return false; }
+	virtual bool GoPrev(void) { DeactivateMenu(); return false; }
+	virtual bool GoDown(void) { return GoNext(); }
+	virtual bool GoUp(void) { return GoPrev(); }
+	virtual bool GoDownStill(void) { return false; }
+	virtual bool GoUpStill(void) { return false; }
+	virtual bool GoLeft(void) { SelectCurrentOptionUnderCursor(); return true; }
+	virtual bool GoRight(void) { SelectCurrentOptionUnderCursor(); return true; }
+	virtual bool GoLeftStill(void) { return true; }
+	virtual bool GoRightStill(void) { return true; }
+	virtual bool GoFirst(void) { ActivateMenu(true); return true; }
+	virtual bool GoLast(void) { ActivateMenu(true); return true; }
+	virtual void SelectCurrentOptionUnderCursor(void) { m_title.m_bSelected ^= 1; }
+	virtual void SelectDefaultCancelAction(void) {}
+	virtual void ActivateMenu(bool first) { m_bActive = true; }
+	virtual void DeactivateMenu(void) { m_bActive = false; }
+	virtual int GetMenuSelection(void) { return m_title.m_bSelected; }
+	virtual void SetMenuSelection(int selection) { m_title.m_bSelected = selection; }
+};
+
+class CMenuOnOffTriggered : public CMenuOnOff
+{
+public:
+	typedef void (*Trigger)(CMenuOnOffTriggered *);
+
+	Trigger m_trigger;
+
+	void SetOptionPosition(float x, float y, Trigger trigger, bool bRightJustify);
+
+	virtual void SelectCurrentOptionUnderCursor(void);
+};
+
+class CMenuSlider : public CMenuBase
+{
+public:
+	CPlaceableShText m_title;
+	CPlaceableShText m_box;	// not really a text
+	CRGBA m_colors[2];	// left and right
+	CVector2D m_size[2];	// left and right
+	int m_value;
+	CPlaceableShText m_percentageText;
+	bool m_bDrawPercentage;
+//	char field_8D;
+//	char field_8E;
+//	char field_8F;
+	uint8 m_someAlpha;
+//	char field_91;
+//	char field_92;
+//	char field_93;
+	bool m_bActive;
+	int m_style;
+
+	static char Buf8[8];
+	static wchar Buf16[8];
+
+	CMenuSlider(void)
+	 : m_value(0), m_bDrawPercentage(false), m_bActive(false), m_style(0) {}
+
+	void SetColors(const CRGBA &title, const CRGBA &percentage, const CRGBA &left, const CRGBA &right);
+	void DrawTicks(const CVector2D &position, const CVector2D &size, float heightRight, float level, const CRGBA &leftCol, const CRGBA &selCol, const CRGBA &rightCol, bool bShadow, const CVector2D &shadowOffset, const CRGBA &shadowColor);
+	void DrawTicks(const CVector2D &position, const CVector2D &size, float heightRight, float level, const CRGBA &leftCol, const CRGBA &rightCol, bool bShadow, const CVector2D &shadowOffset, const CRGBA &shadowColor);
+	void AddTickBox(float positionX, float positionY, float width, float heigthLeft, float heightRight);
+	void AddTitle(wchar *text, float positionX, float positionY);
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual void DrawNormal(float x, float y);
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
+	virtual void SetAlpha(uint8 alpha);
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
+	virtual bool GoNext(void) { DeactivateMenu(); return false; }
+	virtual bool GoPrev(void) { DeactivateMenu(); return false; }
+	virtual bool GoDown(void) { return GoNext(); }
+	virtual bool GoUp(void) { return GoPrev(); }
+	virtual bool GoDownStill(void) { return false; }
+	virtual bool GoUpStill(void) { return false; }
+	virtual bool GoLeft(void) { if(m_value < 0) m_value = 0; return true; }
+	virtual bool GoRight(void) { if(m_value > 1000) m_value = 1000; return true; }
+	virtual bool GoLeftStill(void) { m_value -= 8; if(m_value < 0) m_value = 0; return true; }
+	virtual bool GoRightStill(void) { m_value += 8; if(m_value > 1000) m_value = 1000; return true; }
+	virtual bool GoFirst(void) { ActivateMenu(true); return true; }
+	virtual bool GoLast(void) { ActivateMenu(true); return true; }
+	virtual void SelectCurrentOptionUnderCursor(void) {}
+	virtual void SelectDefaultCancelAction(void) {}
+	virtual void ActivateMenu(bool first) { m_bActive = true; }
+	virtual void DeactivateMenu(void) { m_bActive = false; }
+	virtual int GetMenuSelection(void) { return m_value/10; }
+	virtual void SetMenuSelection(int selection) { m_value = selection*10; }
+};
+
+class CMenuSliderTriggered : public CMenuSlider
+{
+public:
+	typedef void (*Trigger)(CMenuSliderTriggered *);
+
+	Trigger m_trigger;
+	Trigger m_alwaysTrigger;
+
+	CMenuSliderTriggered(void)
+	 : m_trigger(nil), m_alwaysTrigger(nil) {}
+
+	void AddTickBox(float positionX, float positionY, float width, float heigthLeft, float heightRight, Trigger trigger, Trigger alwaysTrigger);
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual bool GoLeft(void);
+	virtual bool GoRight(void);
+	virtual bool GoLeftStill(void);
+	virtual bool GoRightStill(void);
+};
+
+
+class CMenuLineLister : public CMenuBase
+{
+public:
+	float m_width;
+	float m_height;
+	int m_numLines;
+	CPlaceableShText m_linesLeft[NUM_LINELISTER_LINES_TOTAL];
+	CPlaceableShText m_linesRight[NUM_LINELISTER_LINES_TOTAL];
+	uint8 m_lineAlphas[NUM_LINELISTER_LINES_TOTAL];
+	int8 m_lineFade[NUM_LINELISTER_LINES_TOTAL];
+	float m_scrollPosition;
+	float m_scrollSpeed;
+	int field_10E8;
+	float m_lineSpacing;
+
+	CMenuLineLister(void);
+
+	void SetLinesColor(const CRGBA &color);
+	void ResetNumberOfTextLines(void);
+	bool AddTextLine(wchar *left, wchar *right);
+
+	CPlaceableShText *GetLeftLine(int i) { return &m_linesLeft[(i%NUM_LINELISTER_LINES) + 15]; };
+	CPlaceableShText *GetRightLine(int i) { return &m_linesRight[(i%NUM_LINELISTER_LINES) + 15]; };
+
+	virtual void Draw(const CRGBA &optionHighlight, const CRGBA &titleHighlight, float x, float y);
+	virtual void DrawNormal(float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
+	virtual void DrawHighlighted(const CRGBA &titleHighlight, float x, float y) { Draw(CRGBA(0,0,0,0), CRGBA(0,0,0,0), x, y); }
+	virtual void SetAlpha(uint8 alpha);
+	virtual void SetShadows(bool bDropShadows, const CRGBA &shadowColor, const CVector2D &shadowOffset);
+	virtual bool GoNext(void) { return false; }
+	virtual bool GoPrev(void) { return false; }
+	virtual bool GoDown(void) { return GoNext(); }
+	virtual bool GoUp(void) { return GoPrev(); }
+	virtual bool GoDownStill(void) { m_scrollSpeed = 0.0f; return true; }
+	virtual bool GoUpStill(void) { m_scrollSpeed *= 6.0f; return true; }
+	virtual bool GoLeft(void) { return true; }
+	virtual bool GoRight(void) { return true; }
+	virtual bool GoLeftStill(void) { return true; }
+	virtual bool GoRightStill(void) { return true; }
+	virtual bool GoFirst(void) { return true; }
+	virtual bool GoLast(void) { return true; }
+	virtual void SelectCurrentOptionUnderCursor(void) {}
+	virtual void SelectDefaultCancelAction(void) {}
+	virtual void ActivateMenu(bool first) {}
+	virtual void DeactivateMenu(void) {}
+	virtual int GetMenuSelection(void) { return -1; }
+	virtual void SetMenuSelection(int selection) {}
+};
+
+class CMenuPage
+{
+public:
+	CMenuBase *m_controls[NUM_PAGE_WIDGETS];
+	int m_numControls;
+	CMenuBase *m_pCurrentControl;
+	int m_cursor;
+
+	CMenuPage(void) { Initialise(); }
+	void Initialise(void);
+	bool AddMenu(CMenuBase *widget);
+
+	bool IsActiveMenuTwoState(void);
+	void ActiveMenuTwoState_SelectNextPosition(void);
+	void Draw(const CRGBA &,const CRGBA &, float, float);
+	void DrawHighlighted(const CRGBA &titleHighlight, float x, float y);
+	void DrawNormal(float x, float y);
+	void ActivatePage(void);
+	void SetAlpha(uint8 alpha);
+	void SetShadows(bool, const CRGBA &, const CVector2D &);
+	void GoPrev(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoPrev()) m_pCurrentControl->GoLast(); } }
+	void GoNext(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoNext()) m_pCurrentControl->GoFirst(); } }
+	void GoLeft(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoLeft()) m_pCurrentControl->GoLast(); } }
+	void GoRight(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoRight()) m_pCurrentControl->GoFirst(); } }
+	void GoUp(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoUp()) m_pCurrentControl->GoLast(); } }
+	void GoDown(void) { if(m_pCurrentControl) { if(!m_pCurrentControl->GoDown()) m_pCurrentControl->GoFirst(); } }
+	void GoLeftStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoLeftStill(); }
+	void GoRightStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoRightStill(); }
+	void GoUpStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoUpStill(); }
+	void GoDownStill(void) { if(m_pCurrentControl) m_pCurrentControl->GoDownStill(); }
+	void SelectDefaultCancelAction(void) { if(m_pCurrentControl) m_pCurrentControl->SelectDefaultCancelAction(); }
+	void SelectCurrentOptionUnderCursor(void) { if(m_pCurrentControl) m_pCurrentControl->SelectCurrentOptionUnderCursor(); }
+
+	virtual void GoUpMenuOnPage(void);
+	virtual void GoDownMenuOnPage(void);
+	virtual void GoLeftMenuOnPage(void);
+	virtual void GoRightMenuOnPage(void);
+};
+
+class CMenuPageAnyMove : public CMenuPage
+{
+public:
+	FEC_MOVETAB m_moveTab[NUM_PAGE_WIDGETS];
+
+	CMenuPageAnyMove(void) { Initialise(); }
+	void Initialise(void);
+	using CMenuPage::AddMenu;
+	bool AddMenu(CMenuBase *widget, FEC_MOVETAB *moveTab);
+
+	virtual void GoUpMenuOnPage(void);
+	virtual void GoDownMenuOnPage(void);
+	virtual void GoLeftMenuOnPage(void);
+	virtual void GoRightMenuOnPage(void);
+};
\ No newline at end of file
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 74729fec..75effc8a 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -8,6 +8,7 @@
 #include "Pad.h"
 #include "Text.h"
 #include "main.h"
+#include "RwHelper.h"
 #include "Timer.h"
 #include "Game.h"
 #include "DMAudio.h"
@@ -27,11 +28,48 @@
 #include "World.h"
 #include "Renderer.h"
 #include "CdStream.h"
+#include "Radar.h"
+#include "Stats.h"
+#include "Messages.h"
+#include "FileLoader.h"
 
-#define DONT_USE_SUSPICIOUS_FUNCS 1
 #define TIDY_UP_PBP // ProcessButtonPresses
 #define MAX_VISIBLE_LIST_ROW 30
-#define LIST_HEIGHT 263.0f
+#define SCROLLBAR_MAX_HEIGHT 263.0f // not in end result
+
+#ifdef USE_PRECISE_MEASUREMENT_CONVERTION
+#define MILES_IN_METER 0.000621371192f
+#define FEET_IN_METER 3.28084f
+#else
+#define MILES_IN_METER 0.00059880241f
+#define FEET_IN_METER 3.33f
+#endif
+
+#ifdef SCROLLABLE_STATS_PAGE
+#define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS)
+#else
+#define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS)
+#endif
+
+#ifdef TRIANGLE_BACK_BUTTON
+#define GetBackJustUp GetTriangleJustUp
+#define GetBackJustDown GetTriangleJustDown
+#elif defined(CIRCLE_BACK_BUTTON)
+#define GetBackJustUp GetCircleJustUp
+#define GetBackJustDown GetCircleJustDown
+#else
+#define GetBackJustUp GetSquareJustUp
+#define GetBackJustDown GetSquareJustDown
+#endif
+
+#ifdef MENU_MAP
+bool CMenuManager::bMenuMapActive = false;
+bool CMenuManager::bMapMouseShownOnce = false;
+bool CMenuManager::bMapLoaded = false;
+float CMenuManager::fMapSize;
+float CMenuManager::fMapCenterY;
+float CMenuManager::fMapCenterX;
+#endif
 
 #ifdef PS2_LIKE_MENU
 BottomBarOption bbNames[8];
@@ -44,56 +82,66 @@ int curBottomBarOption = -1;
 int hoveredBottomBarOption = -1;
 #endif
 
-WRAPPER void CMenuManager::PrintController(void) { EAXJMP(0x483990); }
+int32 CMenuManager::OS_Language = LANG_ENGLISH; // *(int32*)0x5F2F78;
+int8 CMenuManager::m_PrefsUseVibration; // = *(int8*)0x95CD92;
+int8 CMenuManager::m_DisplayControllerOnFoot; // = *(int8*)0x95CD8D;
+int8 CMenuManager::m_PrefsVsync = 1; // *(int8*)0x5F2E58;
+int8 CMenuManager::m_PrefsVsyncDisp = 1; // *(int8*)0x5F2E5C;
+int8 CMenuManager::m_PrefsFrameLimiter = 1; // *(int8*)0x5F2E60;
+int8 CMenuManager::m_PrefsShowSubtitles = 1; // *(int8*)0x5F2E54;
+int8 CMenuManager::m_PrefsSpeakers; // = *(int8*)0x95CD7E;
+int32 CMenuManager::m_ControlMethod; // = *(int32*)0x8F5F7C;
+int8 CMenuManager::m_PrefsDMA = 1; // *(int8*)0x5F2F74;
+int32 CMenuManager::m_PrefsLanguage; // = *(int32*)0x941238;
+uint8 CMenuManager::m_PrefsStereoMono; // *(bool*)0x95CDB5; // unused except restore settings
 
-int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78;	// 9
-int8 &CMenuManager::m_PrefsUseVibration = *(int8*)0x95CD92;
-int8 &CMenuManager::m_DisplayControllerOnFoot = *(int8*)0x95CD8D;
-int8 &CMenuManager::m_PrefsVsync = *(int8*)0x5F2E58;	// 1
-int8 &CMenuManager::m_PrefsVsyncDisp = *(int8*)0x5F2E5C;	// 1
-int8 &CMenuManager::m_PrefsFrameLimiter = *(int8*)0x5F2E60;	// 1
-int8 &CMenuManager::m_PrefsShowSubtitles = *(int8*)0x5F2E54;	// 1
-int8 &CMenuManager::m_PrefsSpeakers = *(int8*)0x95CD7E;
-int32 &CMenuManager::m_ControlMethod = *(int32*)0x8F5F7C;
-int8 &CMenuManager::m_PrefsDMA = *(int8*)0x5F2F74;	// 1
-int32 &CMenuManager::m_PrefsLanguage = *(int32*)0x941238;
+bool CMenuManager::m_PrefsAllowNastyGame = true; // *(bool*)0x5F2E64;
+bool CMenuManager::m_bStartUpFrontEndRequested; // = *(bool*)0x95CCF4;
+bool CMenuManager::m_bShutDownFrontEndRequested; // = *(bool*)0x95CD6A;
 
-bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64;	// true
-bool &CMenuManager::m_bStartUpFrontEndRequested = *(bool*)0x95CCF4;
-bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A;
+int8 CMenuManager::m_PrefsUseWideScreen; // = *(int8*)0x95CD23;
+int8 CMenuManager::m_PrefsRadioStation; // = *(int8*)0x95CDA4;
+int32 CMenuManager::m_PrefsBrightness = 256; // = *(int32*)0x5F2E50;
+float CMenuManager::m_PrefsLOD; // = *(float*)0x8F42C4;
+int8 CMenuManager::m_bFrontEnd_ReloadObrTxtGxt; // = *(int8*)0x628CFC;
+int32 CMenuManager::m_PrefsMusicVolume = 102; // = *(int32*)0x5F2E4C;
+int32 CMenuManager::m_PrefsSfxVolume = 102; // = *(int32*)0x5F2E48;
 
-int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23;
-int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4;
-int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50;	// 256
-float &CMenuManager::m_PrefsLOD = *(float*)0x8F42C4;
-int8 &CMenuManager::m_bFrontEnd_ReloadObrTxtGxt = *(int8*)0x628CFC;
-int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C;	// 102
-int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48;	// 102
+char CMenuManager::m_PrefsSkinFile[256] = "$$\"\""; // = (char*)0x5F2E74;
 
-char *CMenuManager::m_PrefsSkinFile = (char*)0x5F2E74;	//[256] "$$\"\""
+int32 CMenuManager::m_KeyPressedCode = -1; // = *(int32*)0x5F2E70;
 
-int32 &CMenuManager::m_KeyPressedCode = *(int32*)0x5F2E70;	// -1
+// Originally that was PS2 option color, they forget it here and used in PrintBriefs once(but didn't use the output anyway)
+#ifdef PS2_LIKE_MENU
+const CRGBA TEXT_COLOR = CRGBA(150, 110, 30, 255);
+#else
+const CRGBA TEXT_COLOR = CRGBA(235, 170, 50, 255); // PC briefs text color
+#endif
 
-float &CMenuManager::menuXYpadding = *(float*)0x5F355C;	// don't know the original name. MENUACTION_X_MARGIN, never changes
-float &CMenuManager::actionTextScaleX = *(float*)0x5F2E40;
-float &CMenuManager::actionTextScaleY = *(float*)0x5F2E44;
+const float menuXYpadding = MENUACTION_POS_Y; // *(float*)0x5F355C;	// not original name
+float MENU_TEXT_SIZE_X = SMALLTEXT_X_SCALE; //*(float*)0x5F2E40;
+float MENU_TEXT_SIZE_Y = SMALLTEXT_Y_SCALE; //*(float*)0x5F2E44;
 
-int32 &CMenuManager::sthWithButtons = *(int32*)0x8E2880;
-int32 &CMenuManager::sthWithButtons2 = *(int32*)0x942F88;
+bool holdingScrollBar; // *(bool*)0x628D59; // not original name
+int32 CMenuManager::m_SelectedMap; // *(int32*)0x8E2880;
+int32 CMenuManager::m_SelectedGameType; // *(int32*)0x942F88;
 
-CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8;
+// Used in a hidden menu
+uint8 CMenuManager::m_PrefsPlayerRed = 255;
+uint8 CMenuManager::m_PrefsPlayerGreen = 128;
+uint8 CMenuManager::m_PrefsPlayerBlue; // why??
+
+CMenuManager FrontEndMenuManager; // = *(CMenuManager*)0x8F59D8;
 
 // Move this somewhere else.
-float &CRenderer::ms_lodDistScale = *(float*)0x5F726C;	// 1.2
+float CRenderer::ms_lodDistScale = 1.2f; // *(float*)0x5F726C;
 
-// Stuff not in CMenuManager:
-uint32 &TimeToStopPadShaking = *(uint32*)0x628CF8;
-char *&pEditString = *(char**)0x628D00;
-int32 *&pControlEdit = *(int32**)0x628D08;
-bool &DisplayComboButtonErrMsg = *(bool*)0x628D14;
-int32 &MouseButtonJustClicked = *(int32*)0x628D0C;
-int32 &JoyButtonJustClicked = *(int32*)0x628D10;
-bool &holdingScrollBar = *(bool*)0x628D59;
+uint32 TimeToStopPadShaking; // = *(uint32*)0x628CF8;
+char *pEditString; // = *(char**)0x628D00;
+int32 *pControlEdit; // = *(int32**)0x628D08;
+bool DisplayComboButtonErrMsg; // = *(bool*)0x628D14;
+int32 MouseButtonJustClicked; // = *(int32*)0x628D0C;
+int32 JoyButtonJustClicked; // = *(int32*)0x628D10;
 //int32 *pControlTemp = 0;
 
 #ifndef MASTER
@@ -131,7 +179,22 @@ const char* FrontendFilenames[][2] = {
 	{"fe_radio7", "" }, // MSX_FM
 	{"fe_radio8", "" }, // FLASHBACK
 	{"fe_radio9", "" }, // CHATTERBOX
-};					
+};
+
+#ifdef MENU_MAP
+const char* MapFilenames[][2] = {
+	{"mapMid01", "mapMid01A"},
+	{"mapMid02", "mapMid02A"},
+	{"mapMid03", "mapMid03A"},
+	{"mapBot01", "mapBot01A"},
+	{"mapBot02", "mapBot02A"},
+	{"mapBot03", "mapBot03A"},
+	{"mapTop01", "mapTop01A"},
+	{"mapTop02", "mapTop02A"},
+	{"mapTop03", "mapTop03A"},
+};
+CSprite2d CMenuManager::m_aMapSprites[NUM_MAP_SPRITES];
+#endif
 
 // 0x5F3344
 const char* MenuFilenames[][2] = {
@@ -160,7 +223,7 @@ const char* MenuFilenames[][2] = {
 #ifdef ASPECT_RATIO_SCALE
 // All of the defines below replace the StretchX function. Otherwise use SCREEN_SCALE_X.
 #define MENU_X_LEFT_ALIGNED(x) ScaleAndCenterX(x)
-#define MENU_X_RIGHT_ALIGNED(x) ScaleAndCenterX(DEFAULT_SCREEN_WIDTH - x)
+#define MENU_X_RIGHT_ALIGNED(x) ScaleAndCenterX(DEFAULT_SCREEN_WIDTH - (x))
 #define MENU_X(x) SCREEN_SCALE_X(x)
 #define MENU_Y(y) SCREEN_SCALE_Y(y)
 float
@@ -183,8 +246,6 @@ ScaleAndCenterX(float x)
 #define MENU_Y(y) StretchY(y)
 #endif
 
-#define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS)
-
 #ifdef PS2_LIKE_MENU
 #define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \
 	do { \
@@ -224,14 +285,14 @@ ScaleAndCenterX(float x)
 
 #define ProcessSlider(value, increaseAction, decreaseAction, hoverStartX, hoverEndX) \
 	do { \
-		lastBarX = DisplaySlider(SCREEN_STRETCH_FROM_RIGHT(MENUSLIDER_X + columnWidth), MENU_Y(bitAboveNextItemY), MENU_Y(freeSpaceInLine), MENU_Y(usableLineHeight), MENU_X(MENUSLIDER_UNK), value); \
+		lastActiveBarX = DisplaySlider(SCREEN_STRETCH_FROM_RIGHT(MENUSLIDER_X + columnWidth), MENU_Y(bitAboveNextItemY), MENU_Y(smallestSliderBar), MENU_Y(usableLineHeight), MENU_X(MENUSLIDER_UNK), value); \
 		if (i != m_nCurrOption || !itemsAreSelectable) \
 			break; \
 		 \
-		if (CheckHover(hoverStartX, lastBarX - MENU_X(10.0f), MENU_Y(nextYToUse), MENU_Y(28.0f + nextYToUse))) \
+		if (CheckHover(hoverStartX, lastActiveBarX - MENU_X(10.0f), MENU_Y(nextYToUse), MENU_Y(28.0f + nextYToUse))) \
 			m_nHoverOption = decreaseAction; \
 		 \
-		if (!CheckHover(MENU_X(10.0f) + lastBarX, hoverEndX, MENU_Y(nextYToUse), MENU_Y(28.0f + nextYToUse))) \
+		if (!CheckHover(MENU_X(10.0f) + lastActiveBarX, hoverEndX, MENU_Y(nextYToUse), MENU_Y(28.0f + nextYToUse))) \
 			break; \
 		 \
 		m_nHoverOption = increaseAction; \
@@ -248,7 +309,7 @@ CMenuManager::ScrollUpListByOne()
 		if (m_nFirstVisibleRowOnList > 0) {
 			m_nSelectedListRow--;
 			m_nFirstVisibleRowOnList--;
-			m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow;
+			m_nScrollbarTopMargin -= SCROLLBAR_MAX_HEIGHT / m_nTotalListRow;
 		}
 	} else {
 		m_nSelectedListRow--;
@@ -262,7 +323,7 @@ CMenuManager::ScrollDownListByOne()
 		if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
 			m_nSelectedListRow++;
 			m_nFirstVisibleRowOnList++;
-			m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow;
+			m_nScrollbarTopMargin += SCROLLBAR_MAX_HEIGHT / m_nTotalListRow;
 		}
 	} else {
 		if (m_nSelectedListRow < m_nTotalListRow - 1) {
@@ -285,7 +346,7 @@ CMenuManager::PageUpList(bool playSoundOnSuccess)
 			m_nFirstVisibleRowOnList = 0;
 			m_nSelectedListRow = 0;
 		}
-		m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+		m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
 	}
 }
 
@@ -303,7 +364,7 @@ CMenuManager::PageDownList(bool playSoundOnSuccess)
 			m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW;
 			m_nSelectedListRow = m_nTotalListRow - 1;
 		}
-		m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+		m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
 	}
 }
 
@@ -335,18 +396,18 @@ CMenuManager::ThingsToDoBeforeLeavingPage()
 // ------ Functions not in the game/inlined ends
 
 void
-CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2)
+CMenuManager::BuildStatLine(char *text, void *stat, bool itsFloat, void *stat2)
 {
 	if (!text)
 		return;
 
 	if (stat2) {
-		if (aFloat) 
+		if (itsFloat) 
 			sprintf(gString2, "  %.2f %s %.2f", *(float*)stat, UnicodeToAscii(TheText.Get("FEST_OO")), *(float*)stat2);
 		else 
 			sprintf(gString2, "  %d %s %d", *(int*)stat, UnicodeToAscii(TheText.Get("FEST_OO")), *(int*)stat2);
 	} else if (stat) {
-		if (aFloat)
+		if (itsFloat)
 			sprintf(gString2, "  %.2f", *(float*)stat);
 		else
 			sprintf(gString2, "  %d", *(int*)stat);
@@ -357,14 +418,12 @@ CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2)
 	AsciiToUnicode(gString2, gUString2);
 }
 
-#if 0
-WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); }
-#else
-void CMenuManager::CentreMousePointer()
+void
+CMenuManager::CentreMousePointer()
 {
 	tagPOINT Point;
 
-	if (SCREEN_WIDTH * 0.5f == 0.0f && 0.0f == SCREEN_HEIGHT * 0.5f) {
+	if (SCREEN_WIDTH * 0.5f != 0.0f && 0.0f != SCREEN_HEIGHT * 0.5f) {
 		Point.x = SCREEN_WIDTH / 2;
 		Point.y = SCREEN_HEIGHT / 2;
 		ClientToScreen(PSGLOBAL(window), &Point);
@@ -374,28 +433,85 @@ void CMenuManager::CentreMousePointer()
 		PSGLOBAL(lastMousePos.y) = SCREEN_HEIGHT / 2;
 	}
 }
-#endif
 
-#if 1
-WRAPPER int CMenuManager::CheckCodesForControls(int32) { EAXJMP(0x48A950); }
-#else
-void CMenuManager::CheckCodesForControls(int, int)
+void
+CMenuManager::CheckCodesForControls(int typeOfControl)
 {
-	DisplayComboButtonErrMsg = 0;
-}
-#endif
+	DisplayComboButtonErrMsg = false;
+	bool invalidKey = false;
+	bool escPressed = false;
+	eControllerType typeToSave;
+	// GetStartOptionsCntrlConfigScreens();
+	e_ControllerAction action = (e_ControllerAction) m_CurrCntrlAction;
 
-#if 0
-WRAPPER bool CMenuManager::CheckHover(int, int, int, int) { EAXJMP(0x48ACA0); }
-#else
-bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2)
+	if (typeOfControl == KEYBOARD) {
+		if (*pControlEdit == rsESC) {
+			escPressed = true;
+		} else if (*pControlEdit > rsF3 && *pControlEdit != rsF9 && *pControlEdit != rsLWIN &&
+			*pControlEdit != rsRWIN && *pControlEdit != rsRALT) {
+			typeToSave = KEYBOARD;
+			if (ControlsManager.GetControllerKeyAssociatedWithAction(action, KEYBOARD) != rsNULL &&
+				*pControlEdit != ControlsManager.GetControllerKeyAssociatedWithAction(action, KEYBOARD)) {
+				typeToSave = OPTIONAL_EXTRA;
+			}
+		} else {
+			invalidKey = true;
+		}
+	} else if (typeOfControl == MOUSE) {
+		typeToSave = MOUSE;
+	} else if (typeOfControl == JOYSTICK) {
+		typeToSave = JOYSTICK;
+		if (ControlsManager.GetIsActionAButtonCombo(action))
+			DisplayComboButtonErrMsg = true;
+	}
+
+	ControlsManager.ClearSettingsAssociatedWithAction(action, typeToSave);
+	if (!DisplayComboButtonErrMsg && !escPressed && !invalidKey) {
+		if (typeOfControl == KEYBOARD) {
+			ControlsManager.DeleteMatchingActionInitiators(action, *pControlEdit, KEYBOARD);
+			ControlsManager.DeleteMatchingActionInitiators(action, *pControlEdit, OPTIONAL_EXTRA);
+		} else {
+			if (typeOfControl == MOUSE) {
+				ControlsManager.DeleteMatchingActionInitiators(action, MouseButtonJustClicked, MOUSE);
+			} else if (typeOfControl == JOYSTICK) {
+				ControlsManager.DeleteMatchingActionInitiators(action, JoyButtonJustClicked, JOYSTICK);
+			}
+		}
+		if (typeOfControl == KEYBOARD) {
+			ControlsManager.SetControllerKeyAssociatedWithAction(action, *pControlEdit, typeToSave);
+
+		} else if (typeOfControl == MOUSE) {
+			ControlsManager.SetControllerKeyAssociatedWithAction(action, MouseButtonJustClicked, typeToSave);
+		} else {
+			if (typeOfControl == JOYSTICK) {
+				ControlsManager.SetControllerKeyAssociatedWithAction(action, JoyButtonJustClicked, typeToSave);
+			}
+		}
+		pControlEdit = nil;
+		m_bWaitingForNewKeyBind = false;
+		m_KeyPressedCode = -1;
+		m_bStartWaitingForKeyBind = false;
+		SaveSettings();
+	}
+
+	if (escPressed) {
+		pControlEdit = nil;
+		m_bWaitingForNewKeyBind = false;
+		m_KeyPressedCode = -1;
+		m_bStartWaitingForKeyBind = false;
+		SaveSettings();
+	}
+}
+
+bool
+CMenuManager::CheckHover(int x1, int x2, int y1, int y2)
 {
 	return m_nMousePosX > x1 && m_nMousePosX < x2 &&
 	       m_nMousePosY > y1 && m_nMousePosY < y2;
 }
-#endif
 
-void CMenuManager::CheckSliderMovement(int value)
+void
+CMenuManager::CheckSliderMovement(int value)
 {
 	switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) {
 	case MENUACTION_BRIGHTNESS:
@@ -431,110 +547,113 @@ void CMenuManager::CheckSliderMovement(int value)
 	SaveSettings();
 }
 
-#if 1
-WRAPPER int CMenuManager::CostructStatLine(int) { EAXJMP(0x482800); }
-#else
-int CMenuManager::CostructStatLine(int)
+void
+CMenuManager::DisplayHelperText()
 {
+	// there was a unused static bool
+	static uint32 LastFlash = 0;
+	int32 alpha;
 
-}
-#endif
+	if (m_nHelperTextMsgId != 0 && m_nHelperTextMsgId != 1) {
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::DisplayHelperText() { EAXJMP(0x48B490); }
-#else
-void CMenuManager::DisplayHelperText()
-{
-	static int32 AlphaText = 255;
-	static int32 Time = 0;
-
-	if (m_nHelperTextMsgId && m_nHelperTextMsgId != 1) {
-		if (CTimer::GetTimeInMillisecondsPauseMode() - Time > 10) {
-			Time = CTimer::GetTimeInMillisecondsPauseMode();
+		// FIX: High fps bug
+#ifndef FIX_BUGS
+		if (CTimer::GetTimeInMillisecondsPauseMode() - LastFlash > 10) {
+			LastFlash = CTimer::GetTimeInMillisecondsPauseMode();
 			m_nHelperTextAlpha -= 2;
-
-			if (AlphaText < 1)
-				ResetHelperText();
-
-			AlphaText = m_nHelperTextAlpha > 255 ? 255 : m_nHelperTextAlpha;
 		}
+#else
+		static float fadeAlpha = 0.0f; // To keep it precisely
+		if (m_nHelperTextAlpha >= 255 && fadeAlpha < 250) fadeAlpha = m_nHelperTextAlpha;
+
+		// -2 per every 33 ms (1000.f/30.f - original frame limiter fps)
+		fadeAlpha -= (frameTime / 33.0f) * 2.0f;
+		m_nHelperTextAlpha = fadeAlpha;
+#endif
+		if (m_nHelperTextAlpha < 1)
+			ResetHelperText();
+
+		alpha = m_nHelperTextAlpha > 255 ? 255 : m_nHelperTextAlpha;
 	}
 
-	wchar *HelperTextToPrint = nil;
+	CFont::SetCentreOn();
+	CFont::SetScale(SCREEN_SCALE_X(SMALLESTTEXT_X_SCALE), SCREEN_SCALE_Y(SMALLESTTEXT_Y_SCALE));
+	CFont::SetFontStyle(FONT_HEADING);
+
 	// TODO: name this cases?
 	switch (m_nHelperTextMsgId) {
-	case 0:
-		HelperTextToPrint = TheText.Get("FET_MIG");
-		break;
-	case 1:
-		HelperTextToPrint = TheText.Get("FET_APP");
-		break;
-	case 2:
-		HelperTextToPrint = TheText.Get("FET_HRD");
-		break;
-	case 3:
-		HelperTextToPrint = TheText.Get("FET_RSO");
-		break;
-	case 4:
-		HelperTextToPrint = TheText.Get("FET_RSC");
-		break;
-	default:
-		break;
+		case 0:
+		{
+			int action = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action;
+			if (action != MENUACTION_CHANGEMENU && action != MENUACTION_REDEFCTRL && action != MENUACTION_RESTOREDEF) {
+				CFont::SetColor(CRGBA(255, 255, 255, 255));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(320.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f), TheText.Get("FET_MIG"));
+			}
+			break;
+		}
+		case 1:
+			CFont::SetColor(CRGBA(255, 255, 255, 255));
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(320.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f), TheText.Get("FET_APP"));
+			break;
+		case 2:
+			CFont::SetColor(CRGBA(255, 255, 255, alpha));
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(320.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f), TheText.Get("FET_HRD"));
+			break;
+		case 3:
+			CFont::SetColor(CRGBA(255, 255, 255, alpha));
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(320.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f), TheText.Get("FET_RSO"));
+			break;
+		case 4:
+			CFont::SetColor(CRGBA(255, 255, 255, alpha));
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(320.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f), TheText.Get("FET_RSC"));
+			break;
+		default:
+			break;
 	}
-
-	CFont::SetAlignment(ALIGN_CENTER);
-	CFont::SetScale(SCREEN_SCALE_X(0.4f), SCREEN_SCALE_Y(0.6f));
-	CFont::SetFontStyle(FONT_HEADING);
-	CFont::SetDropColor(CRGBA(0, 0, 0, AlphaText));
-	CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE);
-	CFont::SetColor(CRGBA(255, 255, 255, AlphaText));
-
-	CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_SCALE_FROM_BOTTOM(120.0f), HelperTextToPrint);
+	CFont::SetRightJustifyOff();
 }
-#endif
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER int CMenuManager::DisplaySlider(float, float, float, float, float, float) { EAXJMP(0x488420); }
-#else
-int CMenuManager::DisplaySlider(float x, float y, float leftSize, float rightSize, float rectSize, float progress) 
+int
+CMenuManager::DisplaySlider(float x, float y, float mostLeftBarSize, float mostRightBarSize, float rectSize, float progress) 
 {
 	CRGBA color;
-	float sizeRange;
+	float maxBarHeight;
 
-	float input = 0.0f;
+	int lastActiveBarX = 0;
+	float curBarX = 0.0f;
+	float spacing = SCREEN_SCALE_X(10.0f);
 	for (int i = 0; i < 16; i++) {
-		input = i * rectSize/16.0f + x;
+		curBarX = i * rectSize/16.0f + x;
 
-		if (i/16.0f + 1/32.0f < progress)
+		if (i / 16.0f + 1 / 32.0f < progress) {
 			color = CRGBA(255, 217, 106, FadeIn(255));
-		else
+			lastActiveBarX = curBarX;
+		} else
 			color = CRGBA(185, 120, 0, FadeIn(255));
 
-		sizeRange = max(leftSize, rightSize);
+		maxBarHeight = max(mostLeftBarSize, mostRightBarSize);
 
-		float _x = i * rectSize/16.0f + x;
-		float _y = y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f;
-		float _w = SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x;
-		float _h = y + sizeRange;
-		float _s = SCREEN_SCALE_X(2.0f);
-		CSprite2d::DrawRect(CRect(_x + _s, _y + _s, _w + _s, _h + _s), CRGBA(0, 0, 0, FadeIn(255))); // Shadow
-		CSprite2d::DrawRect(CRect(i * rectSize/16.0f + x, y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f, SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x, y + sizeRange), color);
+		float curBarFreeSpace = ((16 - i) * mostLeftBarSize + i * mostRightBarSize) / 16.0f;
+		float left = curBarX;
+		float top = y + maxBarHeight - curBarFreeSpace;
+		float right = spacing + curBarX;
+		float bottom = y + maxBarHeight;
+		float shadowOffset = SCREEN_SCALE_X(2.0f);
+		CSprite2d::DrawRect(CRect(left + shadowOffset, top + shadowOffset, right + shadowOffset, bottom + shadowOffset), CRGBA(0, 0, 0, FadeIn(200))); // Shadow
+		CSprite2d::DrawRect(CRect(left, top, right, bottom), color);
 	}
-	return input;
+	return lastActiveBarX;
 }
-#endif
 
-#if 0
-WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame() { EAXJMP(0x48AB40); }
-#else
-void CMenuManager::DoSettingsBeforeStartingAGame()
+void
+CMenuManager::DoSettingsBeforeStartingAGame()
 {
 	CCamera::m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDARD;
 	if (m_PrefsVsyncDisp != m_PrefsVsync)
 		m_PrefsVsync = m_PrefsVsyncDisp;
 
 	DMAudio.Service();
-	m_bStartGameLoading = true;
+	m_bWantToRestart = true;
 
 	ShutdownJustMenu();
 	UnloadTextures();
@@ -542,20 +661,17 @@ void CMenuManager::DoSettingsBeforeStartingAGame()
 	DMAudio.SetMusicFadeVol(0);
 	DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds());
 }
-#endif
 
-#if 0
-WRAPPER void CMenuManager::Draw() { EAXJMP(0x47AE00); }
-#else
-void CMenuManager::Draw()
+void
+CMenuManager::Draw()
 {
 	CFont::SetBackgroundOff();
 	CFont::SetPropOn();
 	CFont::SetCentreOff();
 	CFont::SetJustifyOn();
 	CFont::SetBackGroundOnlyTextOn();
-	CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENUACTION_X_MARGIN));
-	CFont::SetRightJustifyWrap(SCREEN_SCALE_X(38.0f));
+	CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN));
+	CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH));
 
 	switch (m_nCurrScreen) {
 		case MENUPAGE_STATS:
@@ -564,6 +680,11 @@ void CMenuManager::Draw()
 		case MENUPAGE_BRIEFS:
 			PrintBriefs();
 			break;
+#ifdef MENU_MAP
+		case MENUPAGE_MAP:
+			PrintMap();
+			break;
+#endif
 	}
 
 	// Header height isn't accounted, we will add that later.
@@ -591,8 +712,8 @@ void CMenuManager::Draw()
 	}
 
 	CFont::SetFontStyle(FONTJAP(FONT_BANK));
-	CFont::SetScale(MENU_X(0.9f * actionTextScaleX), MENU_Y(0.9f * actionTextScaleY));
-	CFont::SetRightJustifyOff(); // AG used SetAlignment(ALIGN_LEFT);
+	CFont::SetScale(MENU_X(MENUACTION_SCALE_MULT * MENU_TEXT_SIZE_X), MENU_Y(MENUACTION_SCALE_MULT * MENU_TEXT_SIZE_Y));
+	CFont::SetRightJustifyOff();
 	CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
 
 	// Label
@@ -623,10 +744,10 @@ void CMenuManager::Draw()
 		}
 
 #ifdef FIX_BUGS
-		// Label is wrapped from right by StretchX(40)px, but wrapped from left by 40px. And this is only place R* didn't use StretchX in menu.
-		CFont::PrintString(MENU_X_LEFT_ALIGNED(MENUACTION_X_MARGIN), MENU_Y(menuXYpadding), str);
+		// Label is wrapped from right by StretchX(40)px, but wrapped from left by 40px. And this is only place R* didn't use StretchX in here.
+		CFont::PrintString(MENU_X_LEFT_ALIGNED(MENU_X_MARGIN), MENU_Y(menuXYpadding), str);
 #else
-		CFont::PrintString(MENUACTION_X_MARGIN, menuXYpadding, str);
+		CFont::PrintString(MENU_X_MARGIN, menuXYpadding, str);
 #endif
 	}
 
@@ -647,7 +768,7 @@ void CMenuManager::Draw()
 			headerHeight = 240;
 			lineHeight = 24;
 			CFont::SetFontStyle(FONTJAP(FONT_HEADING));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.75f), MENU_Y(actionTextScaleY = 0.9f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = BIGTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = BIGTEXT_Y_SCALE));
 			CFont::SetCentreOn();
 			break;
 		case MENUPAGE_SOUND_SETTINGS:
@@ -664,7 +785,7 @@ void CMenuManager::Draw()
 			headerHeight = 0;
 			lineHeight = 20;
 			CFont::SetFontStyle(FONTJAP(FONT_HEADING));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.55f), MENU_Y(actionTextScaleY = 0.8f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = MEDIUMTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = MEDIUMTEXT_Y_SCALE));
 			CFont::SetRightJustifyOff();
 			break;
 		case MENUPAGE_CHOOSE_LOAD_SLOT:
@@ -674,7 +795,7 @@ void CMenuManager::Draw()
 			headerHeight = 38;
 			lineHeight = 20;
 			CFont::SetFontStyle(FONTJAP(FONT_BANK));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.45f), MENU_Y(actionTextScaleY = 0.7f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = SMALLTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = SMALLTEXT_Y_SCALE));
 			CFont::SetRightJustifyOff();
 			break;
 		case MENUPAGE_NEW_GAME_RELOAD:
@@ -686,7 +807,7 @@ void CMenuManager::Draw()
 			headerHeight = 60;
 			lineHeight = 24;
 			CFont::SetFontStyle(FONTJAP(FONT_HEADING));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.75f), MENU_Y(actionTextScaleY = 0.9f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = BIGTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = BIGTEXT_Y_SCALE));
 			CFont::SetCentreOn();
 			break;
 		case MENUPAGE_START_MENU:
@@ -694,7 +815,7 @@ void CMenuManager::Draw()
 			headerHeight = 140;
 			lineHeight = 24;
 			CFont::SetFontStyle(FONTJAP(FONT_HEADING));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.75f), MENU_Y(actionTextScaleY = 0.9f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = BIGTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = BIGTEXT_Y_SCALE));
 			CFont::SetCentreOn();
 			break;
 		case MENUPAGE_PAUSE_MENU:
@@ -702,7 +823,7 @@ void CMenuManager::Draw()
 			headerHeight = 117;
 			lineHeight = 24;
 			CFont::SetFontStyle(FONTJAP(FONT_HEADING));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.75f), MENU_Y(actionTextScaleY = 0.9f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = BIGTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = BIGTEXT_Y_SCALE));
 			CFont::SetCentreOn();
 			break;
 #ifdef PS2_SAVE_DIALOG
@@ -711,7 +832,7 @@ void CMenuManager::Draw()
 			headerHeight = 60;
 			lineHeight = 24;
 			CFont::SetFontStyle(FONTJAP(FONT_BANK));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.75f), MENU_Y(actionTextScaleY = 0.9f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = BIGTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = BIGTEXT_Y_SCALE));
 			break;
 #endif
 		default:
@@ -719,11 +840,15 @@ void CMenuManager::Draw()
 			headerHeight = 40;
 			lineHeight = 24;
 			CFont::SetFontStyle(FONTJAP(FONT_HEADING));
-			CFont::SetScale(MENU_X(actionTextScaleX = 0.75f), MENU_Y(actionTextScaleY = 0.9f));
+			CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = BIGTEXT_X_SCALE), MENU_Y(MENU_TEXT_SIZE_Y = BIGTEXT_Y_SCALE));
 			CFont::SetCentreOn();
 			break;
 	}
 
+#ifdef PS2_LIKE_MENU
+	CFont::SetFontStyle(FONT_BANK);
+#endif
+
 	switch (m_nCurrScreen) {
 		case MENUPAGE_CONTROLLER_PC_OLD1:
 		case MENUPAGE_CONTROLLER_PC_OLD2:
@@ -733,14 +858,14 @@ void CMenuManager::Draw()
 			if (m_bWaitingForNewKeyBind)
 				itemsAreSelectable = false;
 
-			CMenuManager::DrawControllerScreenExtraText(nextYToUse - 8.0f, 350, lineHeight);
+			DrawControllerScreenExtraText(nextYToUse - 8.0f, MENU_X_LEFT_ALIGNED(350), lineHeight);
 			break;
 		default:
 			break;
 	}
 
 	float usableLineHeight = lineHeight * 0.9f; // also height of biggest bar in slider
-	float freeSpaceInLine = lineHeight * 0.1f; // also height of smallest bar in slider(weird)
+	float smallestSliderBar = lineHeight * 0.1f;
 	bool foundTheHoveringItem = false;
 	wchar unicodeTemp[64];
 
@@ -768,7 +893,7 @@ void CMenuManager::Draw()
 			case MENUACTION_CHANGEMENU: {
 				switch (aScreens[m_nCurrScreen].m_aEntries[i].m_TargetMenu) {
 					case MENUPAGE_MULTIPLAYER_MAP:
-						switch (sthWithButtons) {
+						switch (m_SelectedMap) {
 							case 0:
 								rightText = TheText.Get("FEM_MA0");
 								break;
@@ -798,7 +923,7 @@ void CMenuManager::Draw()
 						}
 						break;
 					case MENUPAGE_MULTIPLAYER_MODE:
-						switch (sthWithButtons2) {
+						switch (m_SelectedGameType) {
 							case 0:
 								rightText = TheText.Get("FEN_TY0");
 								break;
@@ -833,7 +958,7 @@ void CMenuManager::Draw()
 				break;
 			}
 			case MENUACTION_CTRLVIBRATION:
-				if (CMenuManager::m_PrefsUseVibration)
+				if (m_PrefsUseVibration)
 					rightText = TheText.Get("FEM_ON");
 				else
 					rightText = TheText.Get("FEM_OFF");
@@ -999,23 +1124,23 @@ void CMenuManager::Draw()
 #endif
 						m_nMousePosY < MENU_Y((nextYToCheck + 2) + usableLineHeight)) {
 
-						static int lastHoveringOption = -99;
-						static int lastScreen = m_nCurrScreen;
+						static int oldOption = -99;
+						static int oldScreen = m_nCurrScreen;
 
 						m_nPrevOption = rowToCheck;
 						if (m_nMouseOldPosX != m_nMousePosX || m_nMouseOldPosY != m_nMousePosY) {
 							m_nCurrOption = rowToCheck;
 							m_bShowMouse = true;
 						}
-						if (lastHoveringOption != m_nCurrOption) {
-							if (lastScreen == m_nCurrScreen && m_bShowMouse)
+						if (oldOption != m_nCurrOption) {
+							if (oldScreen == m_nCurrScreen && m_bShowMouse)
 								DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
 
-							lastHoveringOption = m_nCurrOption;
-							lastScreen = m_nCurrScreen;
+							oldOption = m_nCurrOption;
+							oldScreen = m_nCurrScreen;
 						}
-						if (lastScreen == m_nPrevScreen)
-							lastScreen = m_nCurrScreen;
+						if (oldScreen == m_nPrevScreen)
+							oldScreen = m_nCurrScreen;
 
 						m_nHoverOption = HOVEROPTION_RANDOM_ITEM;
 						foundTheHoveringItem = true;
@@ -1098,7 +1223,7 @@ void CMenuManager::Draw()
 
 			// Sliders
 			// We stretch slider start X here(like original code), because it will always be center of screen
-			int lastBarX;
+			int lastActiveBarX;
 			switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) {
 				case MENUACTION_BRIGHTNESS:
 					ProcessSlider(m_PrefsBrightness / 512.0f, HOVEROPTION_INCREASE_BRIGHTNESS, HOVEROPTION_DECREASE_BRIGHTNESS, MENU_X_LEFT_ALIGNED(170.0f), SCREEN_WIDTH);
@@ -1156,45 +1281,646 @@ void CMenuManager::Draw()
 		break;
 	}
 
-	if (m_nCurrScreen == MENUPAGE_CONTROLLER_SETTINGS) {
+	if (m_nCurrScreen == MENUPAGE_CONTROLLER_SETTINGS)
 		PrintController();
+	else if (m_nCurrScreen == MENUPAGE_SKIN_SELECT_OLD) {
+		CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(180), MENU_Y(98), MENU_X_LEFT_ALIGNED(230), MENU_Y(123)), CRGBA(255, 255, 255, FadeIn(255)));
+		CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(181), MENU_Y(99), MENU_X_LEFT_ALIGNED(229), MENU_Y(122)), CRGBA(m_PrefsPlayerRed, m_PrefsPlayerGreen, m_PrefsPlayerBlue, FadeIn(255)));
 	}
-/*	else if (m_nCurrScreen == MENUPAGE_SKIN_SELECT_OLD) {
-		CSprite2d::DrawRect(CRect(StretchX(180), MENU_Y(98), StretchX(230), MENU_Y(123)), CRGBA(255, 255, 255, FadeIn(255)));
-		CSprite2d::DrawRect(CRect(StretchX(181), MENU_Y(99), StretchX(229), MENU_Y(233)), CRGBA(Player color from PickNewPlayerColour, FadeIn(255)));
+
+}
+
+int
+CMenuManager::GetNumOptionsCntrlConfigScreens(void)
+{
+	int number = 0;
+	switch (m_nCurrScreen) {
+		case MENUPAGE_CONTROLLER_PC_OLD3:
+			number = 2;
+			break;
+		case MENUPAGE_CONTROLLER_DEBUG:
+			number = 4;
+			break;
+		case MENUPAGE_KEYBOARD_CONTROLS:
+			switch (m_ControlMethod) {
+				case CONTROL_STANDARD:
+					number = 25;
+					break;
+				case CONTROL_CLASSIC:
+					number = 30;
+					break;
+			}
+			break;
 	}
-*/
+	return number;
 }
-#endif
 
-#if 1
-WRAPPER void CMenuManager::DrawControllerBound(int, int, int, uint8) { EAXJMP(0x489710); }
-#else
-void CMenuManager::DrawControllerBound(int, int, int, uint8)
-{ 
-
-}
-#endif
-
-#if 1
-WRAPPER void CMenuManager::DrawControllerScreenExtraText(int, int, int) { EAXJMP(0x4892F0); }
-#else
-void CMenuManager::DrawControllerScreenExtraText(int, int, int)
+void
+CMenuManager::DrawControllerBound(int32 yStart, int32 xStart, int32 unused, int8 column)
 {
+	int controllerAction = PED_FIREWEAPON;
+	// GetStartOptionsCntrlConfigScreens();
+	int numOptions = GetNumOptionsCntrlConfigScreens();
+	int bindingMargin = MENU_X(3.0f);
+	float rowHeight;
+	switch (m_ControlMethod) {
+		case CONTROL_STANDARD:
+			rowHeight = CONTSETUP_STANDARD_ROW_HEIGHT;
+			break;
+		case CONTROL_CLASSIC:
+			rowHeight = CONTSETUP_CLASSIC_ROW_HEIGHT;
+			break;
+		default:
+			break;
+	}
 
-}
-#endif
+	// MENU_Y(rowHeight * 0.0f + yStart);
+	for (int optionIdx = 0, nextY = MENU_Y(yStart); optionIdx < numOptions; nextY = MENU_Y(++optionIdx * rowHeight + yStart)) {
+		int nextX = xStart;
+		int bindingsForThisOpt = 0;
+		CFont::SetColor(CRGBA(155, 155, 155, FadeIn(255)));
 
-#if 1
-WRAPPER void CMenuManager::DrawControllerSetupScreen() { EAXJMP(0x481210); }
+		if (column == CONTSETUP_PED_COLUMN) {
+			switch (optionIdx) {
+				case 0:
+					controllerAction = PED_FIREWEAPON;
+					break;
+				case 1:
+					controllerAction = PED_CYCLE_WEAPON_RIGHT;
+					break;
+				case 2:
+					controllerAction = PED_CYCLE_WEAPON_LEFT;
+					break;
+				case 3:
+					controllerAction = GO_FORWARD;
+					break;
+				case 4:
+					controllerAction = GO_BACK;
+					break;
+				case 5:
+					controllerAction = GO_LEFT;
+					break;
+				case 6:
+					controllerAction = GO_RIGHT;
+					break;
+				case 7:
+					controllerAction = PED_SNIPER_ZOOM_IN;
+					break;
+				case 8:
+					controllerAction = PED_SNIPER_ZOOM_OUT;
+					break;
+				case 9:
+					controllerAction = VEHICLE_ENTER_EXIT;
+					break;
+				case 10:
+				case 11:
+				case 12:
+				case 16:
+				case 18:
+				case 19:
+				case 20:
+				case 21:
+					controllerAction = -1;
+					break;
+				case 13:
+					controllerAction = CAMERA_CHANGE_VIEW_ALL_SITUATIONS;
+					break;
+				case 14:
+					controllerAction = PED_JUMPING;
+					break;
+				case 15:
+					controllerAction = PED_SPRINT;
+					break;
+				case 17:
+					controllerAction = PED_LOCK_TARGET;
+					break;
+				case 22:
+					controllerAction = PED_LOOKBEHIND;
+					break;
+				case 23:
+					if (m_ControlMethod == CONTROL_STANDARD)
+						controllerAction = -1;
+					else
+						controllerAction = PED_1RST_PERSON_LOOK_LEFT;
+					break;
+				case 24:
+					if (m_ControlMethod == CONTROL_STANDARD)
+						controllerAction = -1;
+					else
+						controllerAction = PED_1RST_PERSON_LOOK_RIGHT;
+					break;
+				case 25:
+					controllerAction = PED_1RST_PERSON_LOOK_UP;
+					break;
+				case 26:
+					controllerAction = PED_1RST_PERSON_LOOK_DOWN;
+					break;
+				case 27:
+					controllerAction = PED_CYCLE_TARGET_LEFT;
+					break;
+				case 28:
+					controllerAction = PED_CYCLE_TARGET_RIGHT;
+					break;
+				case 29:
+					controllerAction = PED_CENTER_CAMERA_BEHIND_PLAYER;
+					break;
+				default:
+					break;
+			}
+		} else if (column == CONTSETUP_VEHICLE_COLUMN) {
+			switch (optionIdx) {
+				case 0:
+					controllerAction = PED_FIREWEAPON;
+					break;
+				case 1:
+				case 2:
+				case 7:
+				case 8:
+				case 14:
+				case 15:
+				case 17:
+				case 25:
+				case 26:
+				case 27:
+				case 28:
+				case 29:
+					controllerAction = -1;
+					break;
+				case 3:
+					controllerAction = VEHICLE_ACCELERATE;
+					break;
+				case 4:
+					controllerAction = VEHICLE_BRAKE;
+					break;
+				case 5:
+					controllerAction = GO_LEFT;
+					break;
+				case 6:
+					controllerAction = GO_RIGHT;
+					break;
+				case 9:
+					controllerAction = VEHICLE_ENTER_EXIT;
+					break;
+				case 10:
+					controllerAction = VEHICLE_CHANGE_RADIO_STATION;
+					break;
+				case 11:
+					controllerAction = VEHICLE_HORN;
+					break;
+				case 12:
+					controllerAction = TOGGLE_SUBMISSIONS;
+					break;
+				case 13:
+					controllerAction = CAMERA_CHANGE_VIEW_ALL_SITUATIONS;
+					break;
+				case 16:
+					controllerAction = VEHICLE_HANDBRAKE;
+					break;
+				case 18:
+					controllerAction = VEHICLE_TURRETLEFT;
+					break;
+				case 19:
+					controllerAction = VEHICLE_TURRETRIGHT;
+					break;
+				case 20:
+					controllerAction = VEHICLE_TURRETUP;
+					break;
+				case 21:
+					controllerAction = VEHICLE_TURRETDOWN;
+					break;
+				case 22:
+					controllerAction = -2;
+					break;
+				case 23:
+					controllerAction = VEHICLE_LOOKLEFT;
+					break;
+				case 24:
+					controllerAction = VEHICLE_LOOKRIGHT;
+					break;
+				default:
+					break;
+			}
+		}
+		int bindingWhite = 155;
+
+		// Highlight selected column(and make its text black)
+		if (m_nSelectedListRow == optionIdx) {
+			int bgY = m_nSelectedListRow * rowHeight + yStart + 1.0f;
+			if (m_nCurrExLayer == HOVEROPTION_LIST) {
+
+				if (column == CONTSETUP_PED_COLUMN && m_nSelectedContSetupColumn == CONTSETUP_PED_COLUMN) {
+#ifdef FIX_BUGS
+					if (controllerAction == -1) {
+						CSprite2d::DrawRect(CRect(nextX, MENU_Y(bgY), nextX + MENU_X(CONTSETUP_BOUND_COLUMN_WIDTH),
+							MENU_Y(bgY + CONTSETUP_BOUND_HIGHLIGHT_HEIGHT)), CRGBA(235, 170, 50, FadeIn(150)));
+					} else {
+						CSprite2d::DrawRect(CRect(nextX, MENU_Y(bgY), nextX + MENU_X(CONTSETUP_BOUND_COLUMN_WIDTH),
+							MENU_Y(bgY + CONTSETUP_BOUND_HIGHLIGHT_HEIGHT)), CRGBA(255, 217, 106, FadeIn(210)));
+					}
 #else
-void CMenuManager::DrawControllerSetupScreen()
-{
-
-}
+					if (controllerAction == -1) {
+						CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(bgY),
+							MENU_X_LEFT_ALIGNED(400.0f), MENU_Y(bgY + CONTSETUP_BOUND_HIGHLIGHT_HEIGHT)), CRGBA(235, 170, 50, FadeIn(150)));
+					} else {
+						CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(bgY),
+							MENU_X_LEFT_ALIGNED(400.0f), MENU_Y(bgY + CONTSETUP_BOUND_HIGHLIGHT_HEIGHT)), CRGBA(255, 217, 106, FadeIn(210)));
+					}
 #endif
+					CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
+					bindingWhite = 0;
 
-void CMenuManager::DrawFrontEnd()
+				} else if (column == CONTSETUP_VEHICLE_COLUMN && m_nSelectedContSetupColumn == CONTSETUP_VEHICLE_COLUMN) {
+#ifdef FIX_BUGS
+					if (controllerAction == -1) {
+						CSprite2d::DrawRect(CRect(nextX, MENU_Y(bgY), nextX + MENU_X(CONTSETUP_BOUND_COLUMN_WIDTH),
+							MENU_Y(bgY + CONTSETUP_BOUND_HIGHLIGHT_HEIGHT)), CRGBA(235, 170, 50, FadeIn(150)));
+					} else {
+						CSprite2d::DrawRect(CRect(nextX, MENU_Y(bgY), nextX + MENU_X(CONTSETUP_BOUND_COLUMN_WIDTH),
+							MENU_Y(bgY + CONTSETUP_BOUND_HIGHLIGHT_HEIGHT)), CRGBA(255, 217, 106, FadeIn(210)));
+					}
+#else
+					if (controllerAction == -1) {
+						CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(410.0f), MENU_Y(bgY), MENU_X_LEFT_ALIGNED(600.0f), MENU_Y(bgY + 10)), CRGBA(235, 170, 50, FadeIn(150)));
+					} else {
+						CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(410.0f), MENU_Y(bgY), MENU_X_LEFT_ALIGNED(600.0f), MENU_Y(bgY + 10)), CRGBA(255, 217, 106, FadeIn(210)));
+					}
+#endif
+					CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
+					bindingWhite = 0;
+				}
+			}
+		}
+
+		// Print bindings, including seperator (-) between them
+		CFont::SetScale(MENU_X(0.25f), MENU_Y(0.6f));
+		for (int contSetOrder = SETORDER_1; contSetOrder < MAX_SETORDERS && controllerAction != -1; contSetOrder++) {
+			wchar *settingText = ControlsManager.GetControllerSettingTextWithOrderNumber((e_ControllerAction)controllerAction, (eContSetOrder)contSetOrder);
+			if (settingText) {
+				++bindingsForThisOpt;
+				if (bindingsForThisOpt > 1) {
+					wchar *seperator = TheText.Get("FEC_IBT");
+					CFont::SetColor(CRGBA(20, 20, 20, FadeIn(80)));
+					CFont::PrintString(nextX, nextY, seperator);
+					CFont::SetColor(CRGBA(bindingWhite, bindingWhite, bindingWhite, FadeIn(255)));
+					nextX += CFont::GetStringWidth(seperator, true) + bindingMargin;
+				}
+				CFont::PrintString(nextX, nextY, settingText);
+				nextX += CFont::GetStringWidth(settingText, true) + bindingMargin;
+			}
+		}
+		if (controllerAction == -1) {
+			CFont::SetColor(CRGBA(20, 20, 20, FadeIn(80)));
+			CFont::PrintString(nextX, nextY, TheText.Get("FEC_NUS")); // not used
+		} else if (controllerAction == -2) {
+			CFont::SetColor(CRGBA(20, 20, 20, FadeIn(80)));
+			CFont::PrintString(nextX, nextY, TheText.Get("FEC_CMP")); // combo: l+r
+		} else if (bindingsForThisOpt == 0) {
+			if (m_nSelectedListRow != optionIdx) {
+				CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255)));
+				CFont::PrintString(nextX, nextY, TheText.Get("FEC_UNB")); // unbound
+			} else if (m_bWaitingForNewKeyBind) {
+				if (column != m_nSelectedContSetupColumn) {
+					CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255)));
+					CFont::PrintString(nextX, nextY, TheText.Get("FEC_UNB")); // unbound
+				}
+			} else {
+				if (column != m_nSelectedContSetupColumn) {
+					CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255)));
+				}
+				CFont::PrintString(nextX, nextY, TheText.Get("FEC_UNB")); // unbound
+			}
+		}
+
+		if (column == CONTSETUP_PED_COLUMN && m_nSelectedContSetupColumn == CONTSETUP_PED_COLUMN ||
+			column == CONTSETUP_VEHICLE_COLUMN && m_nSelectedContSetupColumn == CONTSETUP_VEHICLE_COLUMN) {
+
+			if (optionIdx == m_nSelectedListRow && controllerAction != -1 && controllerAction != -2) {
+				m_CurrCntrlAction = controllerAction; 
+				if (m_bWaitingForNewKeyBind) {
+					static bool showWaitingText = false;
+					if (bindingsForThisOpt > 0) {
+						wchar *seperator = TheText.Get("FEC_IBT");
+						CFont::PrintString(nextX, nextY, seperator);
+						nextX += CFont::GetStringWidth(seperator, true) + bindingMargin;
+					}
+					static uint32 lastWaitingTextFlash = 0;
+					if (CTimer::GetTimeInMillisecondsPauseMode() - lastWaitingTextFlash > 150) {
+						showWaitingText = !showWaitingText;
+						lastWaitingTextFlash = CTimer::GetTimeInMillisecondsPauseMode();
+					}
+					if (showWaitingText) {
+						CFont::SetColor(CRGBA(55, 55, 55, FadeIn(255)));
+						CFont::PrintString(nextX, nextY, TheText.Get("FEC_QUE")); // "???"
+					}
+					CFont::SetCentreOn();
+					CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+					CFont::SetFontStyle(FONT_HEADING);
+					CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255)));
+					if (m_bKeyChangeNotProcessed) {
+						CFont::PrintString(MENU_X_LEFT_ALIGNED(275.0f), SCREEN_SCALE_FROM_BOTTOM(114.0f), TheText.Get("FET_CIG")); // BACKSPACE TO CLEAR - LMB,RETURN TO CHANGE
+					} else {
+						CFont::PrintString(MENU_X_LEFT_ALIGNED(275.0f), SCREEN_SCALE_FROM_BOTTOM(114.0f), TheText.Get("FET_RIG")); // SELECT A NEW CONTROL FOR THIS ACTION OR ESC TO CANCEL
+					}
+					
+					CFont::SetRightJustifyOff();
+					CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+					CFont::SetFontStyle(0);
+					if (!m_bKeyIsOK)
+						DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
+
+					m_bKeyIsOK = true;
+				} else {
+					CFont::SetCentreOn();
+					CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+					CFont::SetFontStyle(FONT_HEADING);
+					CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255)));
+					CFont::PrintString(MENU_X_LEFT_ALIGNED(275.0f), SCREEN_SCALE_FROM_BOTTOM(114.0f), TheText.Get("FET_CIG")); // BACKSPACE TO CLEAR - LMB,RETURN TO CHANGE
+					CFont::SetRightJustifyOff();
+					CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+					CFont::SetFontStyle(FONT_BANK);
+					m_bKeyIsOK = false;
+					m_bKeyChangeNotProcessed = false;
+				}
+			} else if (optionIdx == m_nSelectedListRow) {
+				CFont::SetCentreOn();
+				CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+				CFont::SetFontStyle(FONT_HEADING);
+				CFont::SetColor(CRGBA(55, 55, 55, FadeIn(255)));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(275.0f), SCREEN_SCALE_FROM_BOTTOM(114.0f), TheText.Get("FET_EIG")); // CANNOT SET A CONTROL FOR THIS ACTION
+				CFont::SetRightJustifyOff();
+				CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+				CFont::SetFontStyle(FONT_BANK);
+			}
+		}
+	}
+}
+
+void
+CMenuManager::DrawControllerScreenExtraText(int yStart, int xStart, int lineHeight)
+{
+	int extraTextStart = GetStartOptionsCntrlConfigScreens();
+	int numOpts = GetNumOptionsCntrlConfigScreens();
+	int spacing = MENU_X(10.0f);
+	for (int i = extraTextStart; i < extraTextStart + numOpts; i++) {
+		int numTextsPrinted = 0;
+		int nextX = xStart;
+		for (int j = 1; j < 5; j++) {
+			wchar *text = ControlsManager.GetControllerSettingTextWithOrderNumber((e_ControllerAction)i, (eContSetOrder)j);
+			if (text)
+				++numTextsPrinted;
+
+			if (text) {
+				// Seperator
+				if (numTextsPrinted > 1) {
+					CFont::PrintString(nextX, MENU_Y(yStart), TheText.Get("FEC_IBT"));
+					nextX = CFont::GetStringWidth(TheText.Get("FEC_IBT"), true) + spacing + nextX;
+				}
+				CFont::PrintString(nextX, MENU_Y(yStart), text);
+			}
+			if (text)
+				nextX = CFont::GetStringWidth(text, true) + spacing + nextX;
+		}
+		if (m_nCurrOption == i - extraTextStart && m_bWaitingForNewKeyBind) {
+			static bool waitingTextVisible = false;
+
+			// Seperator
+			if (numTextsPrinted > 0) {
+				CFont::PrintString(nextX, MENU_Y(yStart), TheText.Get("FEC_IBT"));
+				nextX = CFont::GetStringWidth(TheText.Get("FEC_IBT"), true) + spacing + nextX;
+			}
+			static uint32 lastStateChange = 0;
+			if (CTimer::GetTimeInMillisecondsPauseMode() - lastStateChange > 150) {
+				waitingTextVisible = !waitingTextVisible;
+				lastStateChange = CTimer::GetTimeInMillisecondsPauseMode();
+			}
+			if (waitingTextVisible) {
+				CFont::SetColor(CRGBA(255, 255, 0, FadeIn(255)));
+				CFont::PrintString(nextX, MENU_Y(yStart), TheText.Get("FEC_QUE"));
+				CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+			}
+		}
+		yStart += lineHeight;
+	}
+	wchar *error = nil;
+	if (DisplayComboButtonErrMsg)
+		error = ControlsManager.GetButtonComboText((e_ControllerAction)(m_nCurrOption + extraTextStart));
+
+	if (error) {
+		CFont::SetColor(CRGBA(233, 22, 159, 255));
+		CFont::PrintString(xStart, MENU_Y(yStart + 10), error);
+	}
+}
+
+void
+CMenuManager::DrawControllerSetupScreen()
+{
+	float rowHeight;
+	switch (m_ControlMethod) {
+		case CONTROL_STANDARD:
+			rowHeight = CONTSETUP_STANDARD_ROW_HEIGHT;
+			break;
+		case CONTROL_CLASSIC:
+			rowHeight = CONTSETUP_CLASSIC_ROW_HEIGHT;
+			break;
+		default:
+			break;
+	}
+	CFont::SetBackgroundOff();
+	CFont::SetScale(MENU_X(MENUACTION_SCALE_MULT), MENU_Y(MENUACTION_SCALE_MULT));
+	CFont::SetPropOn();
+	CFont::SetCentreOff();
+	CFont::SetJustifyOn();
+	CFont::SetRightJustifyOff();
+	CFont::SetBackGroundOnlyTextOn();
+	CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN));
+	CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH));
+
+	// Page header
+	CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
+	CFont::SetRightJustifyOn();
+	CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT));
+	CFont::SetFontStyle(FONT_HEADING);
+	switch (m_ControlMethod) {
+		case CONTROL_STANDARD:
+			CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y),
+				TheText.Get(aScreens[m_nCurrScreen].m_ScreenName));
+			break;
+		case CONTROL_CLASSIC:
+			CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y),
+				TheText.Get("FET_CTI"));
+			break;
+		default:
+			break;
+	}
+	wchar *actionTexts[31];
+	actionTexts[0] = TheText.Get("FEC_FIR");
+	actionTexts[1] = TheText.Get("FEC_NWE");
+	actionTexts[2] = TheText.Get("FEC_PWE");
+	actionTexts[3] = TheText.Get("FEC_FOR");
+	actionTexts[4] = TheText.Get("FEC_BAC");
+	actionTexts[5] = TheText.Get("FEC_LEF");
+	actionTexts[6] = TheText.Get("FEC_RIG");
+	actionTexts[7] = TheText.Get("FEC_ZIN");
+	actionTexts[8] = TheText.Get("FEC_ZOT");
+	actionTexts[9] = TheText.Get("FEC_EEX");
+	actionTexts[10] = TheText.Get("FEC_RAD");
+	actionTexts[11] = TheText.Get("FEC_HRN");
+	actionTexts[12] = TheText.Get("FEC_SUB");
+	actionTexts[13] = TheText.Get("FEC_CMR");
+	actionTexts[14] = TheText.Get("FEC_JMP");
+	actionTexts[15] = TheText.Get("FEC_SPN");
+	actionTexts[16] = TheText.Get("FEC_HND");
+	actionTexts[17] = TheText.Get("FEC_TAR");
+	if (m_ControlMethod == CONTROL_CLASSIC) {
+		actionTexts[18] = TheText.Get("FEC_TFL");
+		actionTexts[19] = TheText.Get("FEC_TFR");
+		actionTexts[20] = TheText.Get("FEC_TFU");
+		actionTexts[21] = TheText.Get("FEC_TFD");
+		actionTexts[22] = TheText.Get("FEC_LBA");
+		actionTexts[23] = TheText.Get("FEC_LOL");
+		actionTexts[24] = TheText.Get("FEC_LOR");
+		actionTexts[25] = TheText.Get("FEC_LUD");
+		actionTexts[26] = TheText.Get("FEC_LDU");
+		actionTexts[27] = TheText.Get("FEC_NTR");
+		actionTexts[28] = TheText.Get("FEC_PTT");
+		actionTexts[29] = TheText.Get("FEC_CEN");
+		actionTexts[30] = nil;
+	} else {
+		actionTexts[18] = TheText.Get("FEC_TFL");
+		actionTexts[19] = TheText.Get("FEC_TFR");
+		actionTexts[20] = TheText.Get("FEC_TFU");
+		actionTexts[21] = TheText.Get("FEC_TFD");
+		actionTexts[22] = TheText.Get("FEC_LBA");
+		actionTexts[23] = TheText.Get("FEC_LOL");
+		actionTexts[24] = TheText.Get("FEC_LOR");
+		actionTexts[25] = nil;
+	}
+
+	// Gray panel background
+	CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(CONTSETUP_LIST_LEFT), MENU_Y(CONTSETUP_LIST_TOP),
+		MENU_X_RIGHT_ALIGNED(CONTSETUP_LIST_RIGHT), SCREEN_SCALE_FROM_BOTTOM(CONTSETUP_LIST_BOTTOM)),
+		CRGBA(200, 200, 50, FadeIn(50)));
+
+	if (m_nCurrExLayer == HOVEROPTION_LIST)
+		CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
+	else
+		CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+
+	// List header
+	CFont::SetFontStyle(FONT_HEADING);
+	CFont::SetScale(MENU_X(MENUACTION_SCALE_MULT), MENU_Y(MENUACTION_SCALE_MULT));
+	CFont::SetRightJustifyOff();
+	CFont::PrintString(MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_1_X), MENU_Y(CONTSETUP_LIST_TOP), TheText.Get("FET_CAC"));
+	CFont::PrintString(MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_2_X), MENU_Y(CONTSETUP_LIST_TOP), TheText.Get("FET_CFT"));
+	CFont::PrintString(MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_3_X), MENU_Y(CONTSETUP_LIST_TOP), TheText.Get("FET_CCR"));
+	CFont::SetRightJustifyOff();
+	CFont::SetScale(MENU_X_LEFT_ALIGNED(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+	CFont::SetFontStyle(FONT_BANK);
+	int yStart;
+	if (m_ControlMethod == CONTROL_CLASSIC)
+		yStart = CONTSETUP_LIST_HEADER_HEIGHT + 29;
+	else
+		yStart = CONTSETUP_LIST_HEADER_HEIGHT + 34;
+
+	for (int i = 0; i < ARRAY_SIZE(actionTexts); ++i) {
+		wchar *actionText = actionTexts[i];
+		if (!actionText)
+			break;
+
+		if (m_nMousePosX > MENU_X_LEFT_ALIGNED(CONTSETUP_LIST_LEFT + 2.0f) &&
+			m_nMousePosX < MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_3_X + CONTSETUP_BOUND_COLUMN_WIDTH)) {
+
+			float curOptY = i * rowHeight + yStart;
+			if (m_nMousePosY > MENU_Y(curOptY) && m_nMousePosY < MENU_Y(rowHeight + curOptY)) {
+					if (m_nPrevOption != i && m_nCurrExLayer == HOVEROPTION_LIST)
+						DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+					m_nPrevOption = i;
+					if (m_nMouseOldPosX != m_nMousePosX || m_nMouseOldPosY != m_nMousePosY) {
+						m_nCurrExLayer = HOVEROPTION_LIST;
+						m_nSelectedListRow = i;
+
+						// why different number for 3rd column hovering X?? this function is a mess
+#ifdef FIX_BUGS
+						if (m_nMousePosX > MENU_X_LEFT_ALIGNED(0.0f) && m_nMousePosX < MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_2_X + CONTSETUP_BOUND_COLUMN_WIDTH)) {
+#else
+						if (m_nMousePosX > MENU_X_LEFT_ALIGNED(0.0f) && m_nMousePosX < MENU_X_LEFT_ALIGNED(370.0f)) {
+#endif
+							if (m_nSelectedContSetupColumn != CONTSETUP_PED_COLUMN && m_nCurrExLayer == HOVEROPTION_LIST)
+								DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+							m_nSelectedContSetupColumn = CONTSETUP_PED_COLUMN;
+#ifdef FIX_BUGS
+						} else if (m_nMousePosX > MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_2_X + CONTSETUP_BOUND_COLUMN_WIDTH) && m_nMousePosX < SCREEN_WIDTH) {
+#else
+						} else if (m_nMousePosX > MENU_X_LEFT_ALIGNED(370.0f) && m_nMousePosX < SCREEN_WIDTH) {
+#endif
+							if (m_nSelectedContSetupColumn != CONTSETUP_VEHICLE_COLUMN && m_nCurrExLayer == HOVEROPTION_LIST)
+								DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+							m_nSelectedContSetupColumn = CONTSETUP_VEHICLE_COLUMN;
+						}
+					}
+					// what??
+					if (m_nHoverOption == HOVEROPTION_SKIN) {
+						if (i == m_nSelectedListRow) {
+							m_nHoverOption = HOVEROPTION_NOT_HOVERING;
+							m_bWaitingForNewKeyBind = true;
+							m_bStartWaitingForKeyBind = true;
+							pControlEdit = &m_KeyPressedCode;
+						}
+					} else
+						m_nHoverOption = HOVEROPTION_NOT_HOVERING;
+			}
+		}
+		if (m_nSelectedListRow != 35)
+			CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+		else if (m_nCurrExLayer == HOVEROPTION_LIST)
+			CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
+
+		CFont::SetRightJustifyOff();
+		if (m_PrefsLanguage != LANGUAGE_GERMAN || i != 20 && i != 21)
+			CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE));
+		else
+			CFont::SetScale(MENU_X(0.32f), MENU_Y(SMALLESTTEXT_Y_SCALE));
+
+		CFont::PrintString(MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_1_X), MENU_Y(i * rowHeight + yStart), actionText);
+	}
+	DrawControllerBound(yStart, MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_2_X), rowHeight, CONTSETUP_PED_COLUMN);
+	DrawControllerBound(yStart, MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_3_X), rowHeight, CONTSETUP_VEHICLE_COLUMN);
+	CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X), MENU_Y(MENU_TEXT_SIZE_Y));
+
+	if ((m_nMousePosX > MENU_X_RIGHT_ALIGNED(CONTSETUP_BACK_RIGHT) - CFont::GetStringWidth(TheText.Get("FEDS_TB"), true)
+		&& m_nMousePosX < MENU_X_RIGHT_ALIGNED(CONTSETUP_BACK_RIGHT) && m_nMousePosY > SCREEN_SCALE_FROM_BOTTOM(CONTSETUP_BACK_BOTTOM)
+		&& m_nMousePosY < SCREEN_SCALE_FROM_BOTTOM(CONTSETUP_BACK_BOTTOM - CONTSETUP_BACK_HEIGHT)) || m_nCurrExLayer == HOVEROPTION_BACK) {
+		m_nHoverOption = HOVEROPTION_BACK;
+
+	} else if (m_nMousePosX > MENU_X_LEFT_ALIGNED(CONTSETUP_LIST_LEFT + 2.0f) && m_nMousePosX < MENU_X_LEFT_ALIGNED(CONTSETUP_COLUMN_3_X + CONTSETUP_BOUND_COLUMN_WIDTH)
+		&& m_nMousePosY > MENU_Y(CONTSETUP_LIST_TOP + CONTSETUP_LIST_HEADER_HEIGHT) && m_nMousePosY < SCREEN_SCALE_FROM_BOTTOM(CONTSETUP_LIST_BOTTOM + 5.0f)) {
+		m_nHoverOption = HOVEROPTION_LIST;
+
+	} else {
+		m_nHoverOption = HOVEROPTION_NOT_HOVERING;
+	}
+
+	// Back button and it's shadow
+	CFont::SetFontStyle(FONT_HEADING);
+	CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X), MENU_Y(MENU_TEXT_SIZE_Y));
+	CFont::SetRightJustifyOn();
+	CFont::SetColor(CRGBA(0, 0, 0, FadeIn(90)));
+	for (int i = 0; i < 2; i++) {
+		CFont::PrintString(MENU_X_RIGHT_ALIGNED(CONTSETUP_BACK_RIGHT - 2.0f - i),
+			SCREEN_SCALE_FROM_BOTTOM(CONTSETUP_BACK_BOTTOM - 4.0f - i), TheText.Get("FEDS_TB"));
+
+		if (m_nHoverOption == HOVEROPTION_BACK)
+			CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
+		else
+			CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+	}
+}
+
+void
+CMenuManager::DrawFrontEnd()
 {
 	CFont::SetAlphaFade(255.0f);
 
@@ -1251,7 +1977,8 @@ void CMenuManager::DrawFrontEnd()
 }
 
 #ifdef PS2_SAVE_DIALOG
-void CMenuManager::DrawFrontEndSaveZone()
+void
+CMenuManager::DrawFrontEndSaveZone()
 {
 	CSprite2d::InitPerFrame();
 	CFont::InitPerFrame();
@@ -1263,7 +1990,7 @@ void CMenuManager::DrawFrontEndSaveZone()
 	m_nMenuFadeAlpha = 255;
 	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
 	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
-	CMenuManager::Draw();
+	Draw();
 
 	CFont::DrawFonts();
 
@@ -1294,7 +2021,8 @@ void CMenuManager::DrawFrontEndSaveZone()
 #endif
 
 #ifdef PS2_LIKE_MENU
-void CMenuManager::DrawFrontEndNormal()
+void
+CMenuManager::DrawFrontEndNormal()
 {
 	CSprite2d::InitPerFrame();
 	CFont::InitPerFrame();
@@ -1370,13 +2098,11 @@ void CMenuManager::DrawFrontEndNormal()
 			reverseAlpha = false;
 			ChangeScreen(pendingScreen, pendingOption, true, false);
 		} else {
-			float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
-
 			// +20 per every 33 ms (1000.f/30.f - original frame limiter fps)
 			if (!reverseAlpha)
-				fadeAlpha += (timestep * 100.f) * 20.f / 33.f;
+				fadeAlpha += (frameTime) * 20.f / 33.f;
 			else
-				fadeAlpha = max(0.0f, fadeAlpha - (timestep * 100.f) * 30.f / 33.f);
+				fadeAlpha = max(0.0f, fadeAlpha - (frameTime) * 30.f / 33.f);
 
 			m_nMenuFadeAlpha = fadeAlpha;
 		} 
@@ -1385,8 +2111,7 @@ void CMenuManager::DrawFrontEndNormal()
 		if (lastState == 0) fadeAlpha = 255.f;
 
 		if (reverseAlpha) {
-			float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
-			fadeAlpha -= (timestep * 100.f) * 30.f / 33.f;
+			fadeAlpha -= (frameTime) * 30.f / 33.f;
 
 			m_nMenuFadeAlpha = fadeAlpha;
 		}
@@ -1408,18 +2133,18 @@ void CMenuManager::DrawFrontEndNormal()
 	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
 	switch (m_nCurrScreen) {
 		case MENUPAGE_SKIN_SELECT:
-			CMenuManager::DrawPlayerSetupScreen();
+			DrawPlayerSetupScreen();
 			break;
 		case MENUPAGE_KEYBOARD_CONTROLS:
-			CMenuManager::DrawControllerSetupScreen();
+			DrawControllerSetupScreen();
 			break;
 		default:
-			CMenuManager::Draw();
+			Draw();
 			break;
 	}
 
 	#define optionWidth		MENU_X(66.0f)
-	#define rawOptionHeight	20.0f
+	#define rawOptionHeight	22.0f
 	#define optionBottom	SCREEN_SCALE_FROM_BOTTOM(20.0f)
 	#define optionTop		SCREEN_SCALE_FROM_BOTTOM(20.0f + rawOptionHeight)
 	#define leftPadding		MENU_X_LEFT_ALIGNED(90.0f)
@@ -1427,7 +2152,7 @@ void CMenuManager::DrawFrontEndNormal()
 	hoveredBottomBarOption = -1;
 	if (curBottomBarOption != -1) {
 
-		// This active tab sprite is weird...
+		// This active tab sprite is needlessly big
 		m_aFrontEndSprites[FE2_TABACTIVE].Draw(CRect(leftPadding - MENU_X(2.0f) + (optionWidth) * curBottomBarOption, optionTop,
 			leftPadding - MENU_X(5.0f) + optionWidth * (curBottomBarOption + 2), optionBottom + MENU_Y(rawOptionHeight - 9.0f)),
 			CRGBA(CRGBA(255, 255, 255, 255)));
@@ -1488,7 +2213,8 @@ void CMenuManager::DrawFrontEndNormal()
 	}
 }
 #else
-void CMenuManager::DrawFrontEndNormal()
+void
+CMenuManager::DrawFrontEndNormal()
 {
 	CSprite2d::InitPerFrame();
 	CFont::InitPerFrame();
@@ -1594,10 +2320,8 @@ void CMenuManager::DrawFrontEndNormal()
 		static float fadeAlpha = 0.0f;
 		if (m_nMenuFadeAlpha == 0 && fadeAlpha > 1.0f) fadeAlpha = 0.0f;
 
-		float timestep = CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
-
 		// +20 per every 33 ms (1000.f/30.f - original frame limiter fps)
-		fadeAlpha += (timestep * 100.f) * 20.f / 33.f;
+		fadeAlpha += (frameTime) * 20.f / 33.f;
 		m_nMenuFadeAlpha = fadeAlpha;
 #else
 		static uint32 LastFade = 0;
@@ -1642,13 +2366,13 @@ void CMenuManager::DrawFrontEndNormal()
 	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
 	switch (m_nCurrScreen) {
 		case MENUPAGE_SKIN_SELECT:
-			CMenuManager::DrawPlayerSetupScreen();
+			DrawPlayerSetupScreen();
 			break;
 		case MENUPAGE_KEYBOARD_CONTROLS:
-			CMenuManager::DrawControllerSetupScreen();
+			DrawControllerSetupScreen();
 			break;
 		default:
-			CMenuManager::Draw();
+			Draw();
 			break;
 	}
 
@@ -1680,19 +2404,421 @@ void CMenuManager::DrawFrontEndNormal()
 }
 #endif
 
-#if 1
-WRAPPER void CMenuManager::DrawPlayerSetupScreen() { EAXJMP(0x47F2B0); }
-#else
-void CMenuManager::DrawPlayerSetupScreen()
+void
+CMenuManager::DrawPlayerSetupScreen()
 {
+	CFont::SetBackgroundOff();
+	CFont::SetScale(MENU_X(MENUACTION_SCALE_MULT), MENU_Y(MENUACTION_SCALE_MULT));
+	CFont::SetPropOn();
+	CFont::SetCentreOff();
+	CFont::SetJustifyOn();
+	CFont::SetRightJustifyOff();
+	CFont::SetBackGroundOnlyTextOn();
+	CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN));
+	CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH));
 
-}
+	CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
+	CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT));
+	CFont::SetRightJustifyOn();
+	CFont::SetFontStyle(FONT_HEADING);
+	CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get("FET_PS"));
+
+	// lstrcpy's changed with strcpy
+
+	if (!m_bSkinsEnumerated) {
+		OutputDebugString("Enumerating skin filenames from skins...");
+		m_pSkinListHead.nextSkin = nil;
+		m_pSelectedSkin = &m_pSkinListHead;
+		m_pSelectedSkin->nextSkin = new tSkinInfo;
+		m_pSelectedSkin = m_pSelectedSkin->nextSkin;
+		m_pSelectedSkin->skinId = 0;
+		strcpy(m_pSelectedSkin->skinNameOriginal, "$$\"\"");
+		strcpy(m_pSelectedSkin->skinNameDisplayed, UnicodeToAscii(TheText.Get("FET_DSN")));
+		int nextSkinId = 1;
+		m_pSelectedSkin->nextSkin = nil;
+
+		WIN32_FIND_DATA FindFileData;
+		SYSTEMTIME SystemTime;
+		HANDLE handle = FindFirstFile("skins\\*.bmp", &FindFileData);
+		for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = FindNextFile(handle, &FindFileData)) {
+			if (strncmp(FindFileData.cFileName, "$$\"\"", 5) != 0) {
+				m_pSelectedSkin->nextSkin = new tSkinInfo;
+				m_pSelectedSkin = m_pSelectedSkin->nextSkin;
+				m_pSelectedSkin->skinId = nextSkinId;
+				strcpy(m_pSelectedSkin->skinNameOriginal, FindFileData.cFileName);
+				strcpy(m_pSelectedSkin->skinNameDisplayed, FindFileData.cFileName);
+				FileTimeToSystemTime(&FindFileData.ftLastWriteTime, &SystemTime);
+				GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &SystemTime, 0, m_pSelectedSkin->date, 255);
+				++nextSkinId;
+				m_pSelectedSkin->nextSkin = nil;
+			}
+		}
+		FindClose(handle);
+		m_nSkinsTotal = nextSkinId;
+		char nameTemp[256];
+		for (m_pSelectedSkin = m_pSkinListHead.nextSkin; m_pSelectedSkin; m_pSelectedSkin = m_pSelectedSkin->nextSkin) {
+			// Drop extension
+			int oldLength = strlen(m_pSelectedSkin->skinNameDisplayed);
+			m_pSelectedSkin->skinNameDisplayed[oldLength - 4] = '\0';
+			m_pSelectedSkin->skinNameOriginal[oldLength - 4] = '\0';
+
+			// Fill to 40 bytes-39 chars, idk why. This is done in sepearate function in game.
+			strncpy(nameTemp, m_pSelectedSkin->skinNameDisplayed, 39); // game doesn't do that, but in our day strncpy to same string is forbidden
+			strncpy(m_pSelectedSkin->skinNameDisplayed, nameTemp, 39);
+			if (oldLength - 4 > 39)
+				m_pSelectedSkin->skinNameDisplayed[39] = '\0';
+
+			// Make string lowercase, except first letter
+			strlwr(m_pSelectedSkin->skinNameDisplayed);
+			strncpy(nameTemp, m_pSelectedSkin->skinNameDisplayed, 1);
+			strupr(nameTemp);
+			strncpy(m_pSelectedSkin->skinNameDisplayed, nameTemp, 1);
+
+			// Change some chars
+#ifdef FIX_BUGS
+			for (int k = 0; m_pSelectedSkin->skinNameDisplayed[k] != '\0'; ++k) {
+#else
+			for (int k = 0; m_pSelectedSkin->skinNameOriginal[k] != '\0'; ++k) {
+#endif
+				if (!strncmp(&m_pSelectedSkin->skinNameDisplayed[k], "_", 1))
+					strncpy(&m_pSelectedSkin->skinNameDisplayed[k], " ", 1);
+				if (!strncmp(&m_pSelectedSkin->skinNameDisplayed[k], "@", 1))
+					strncpy(&m_pSelectedSkin->skinNameDisplayed[k], " ", 1);
+				if (!strncmp(&m_pSelectedSkin->skinNameDisplayed[k], "{", 1))
+					strncpy(&m_pSelectedSkin->skinNameDisplayed[k], "(", 1);
+				if (!strncmp(&m_pSelectedSkin->skinNameDisplayed[k], "}", 1))
+					strncpy(&m_pSelectedSkin->skinNameDisplayed[k], ")", 1);
+				if (!strncmp(&m_pSelectedSkin->skinNameDisplayed[k], "�", 1))
+					strncpy(&m_pSelectedSkin->skinNameDisplayed[k], "$", 1);
+			}
+
+			// Make letters after whitespace uppercase
+			for (int l = 0; m_pSelectedSkin->skinNameDisplayed[l] != '\0'; ++l) {
+				if (!strncmp(&m_pSelectedSkin->skinNameDisplayed[l], " ", 1)) {
+					if (m_pSelectedSkin->skinNameDisplayed[l + 1]) {
+						strncpy(nameTemp, &m_pSelectedSkin->skinNameDisplayed[l + 1], 1);
+						strupr(nameTemp);
+						strncpy(&m_pSelectedSkin->skinNameDisplayed[l + 1], nameTemp, 1);
+					}
+				}
+			}
+		}
+		OutputDebugString("Finished enumerating skin files.");
+		m_bSkinsEnumerated = true;
+	}
+	CSprite2d::DrawRect(CRect(MENU_X_LEFT_ALIGNED(PLAYERSETUP_LIST_LEFT), MENU_Y(PLAYERSETUP_LIST_TOP),
+		MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM)), CRGBA(200, 200, 50, FadeIn(50)));
+
+	// Header (Skin - Date)
+	if (m_nCurrExLayer == HOVEROPTION_LIST) {
+		CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
+	} else {
+		CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+	}
+	CFont::SetFontStyle(FONT_HEADING);
+	CFont::SetScale(MENU_X(MENUACTION_SCALE_MULT), MENU_Y(MENUACTION_SCALE_MULT));
+	CFont::SetRightJustifyOn();
+	CFont::PrintString(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_DATE_COLUMN_RIGHT), MENU_Y(PLAYERSETUP_LIST_TOP), TheText.Get("FES_DAT"));
+	switch (m_PrefsLanguage) {
+		case LANGUAGE_FRENCH:
+		case LANGUAGE_SPANISH:
+			CFont::SetScale(MENU_X(0.6f), MENU_Y(MENUACTION_SCALE_MULT));
+			break;
+		default:
+			CFont::SetScale(MENU_X(MENUACTION_SCALE_MULT), MENU_Y(MENUACTION_SCALE_MULT));
+			break;
+	}
+	CFont::SetRightJustifyOff();
+	CFont::PrintString(MENU_X_LEFT_ALIGNED(PLAYERSETUP_SKIN_COLUMN_LEFT), MENU_Y(PLAYERSETUP_LIST_TOP), TheText.Get("FES_SKN"));
+
+	// Skin list
+	CFont::SetRightJustifyOff();
+	CFont::SetScale(MENU_X(PLAYERSETUP_ROW_TEXT_X_SCALE), MENU_Y(PLAYERSETUP_ROW_TEXT_Y_SCALE));
+	CFont::SetFontStyle(FONT_BANK);
+	if (m_nSkinsTotal > 0) {
+		for (m_pSelectedSkin = m_pSkinListHead.nextSkin; m_pSelectedSkin->skinId != m_nFirstVisibleRowOnList;
+			m_pSelectedSkin = m_pSelectedSkin->nextSkin);
+
+		int rowTextY = PLAYERSETUP_LIST_BODY_TOP - 1;
+		int orderInVisibles = 0;
+		int rowEndY = PLAYERSETUP_LIST_BODY_TOP + PLAYERSETUP_ROW_HEIGHT + 1;
+		int rowStartY = PLAYERSETUP_LIST_BODY_TOP;
+		for (int rowIdx = m_nFirstVisibleRowOnList; 
+			rowIdx < m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW && m_pSelectedSkin; ) {
+
+			if (m_nMousePosX > MENU_X_LEFT_ALIGNED(PLAYERSETUP_LIST_LEFT) && m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT)) {
+				if (m_nMousePosY > MENU_Y(rowStartY) && m_nMousePosY < MENU_Y(rowEndY)) {
+					m_nPrevOption = rowIdx;
+					if (m_nMouseOldPosX != m_nMousePosX || m_nMouseOldPosY != m_nMousePosY) {
+						m_nCurrExLayer = HOVEROPTION_LIST;
+					}
+					if (m_nHoverOption == HOVEROPTION_SKIN) {
+						if (rowIdx == m_nSelectedListRow) {
+							m_nHoverOption = HOVEROPTION_NOT_HOVERING;
+							if (m_nSkinsTotal > 0) {
+								DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
+								strcpy(m_PrefsSkinFile, m_aSkinName);
+								CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
+								SaveSettings();
+							}
+						} else {
+							DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+							m_nCurrExLayer = HOVEROPTION_LIST;
+							m_nSelectedListRow = rowIdx;
+							m_nHoverOption = HOVEROPTION_NOT_HOVERING;
+						}
+					}
+				}
+			}
+
+			// Preview skin/change color of row when we focused on another row.
+			if (orderInVisibles == m_nSelectedListRow - m_nFirstVisibleRowOnList) {
+				CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255)));
+				static int lastSelectedSkin = -1;
+				if (m_nSelectedListRow != lastSelectedSkin) {
+					strcpy(m_aSkinName, m_pSelectedSkin->skinNameOriginal);
+					CWorld::Players[0].SetPlayerSkin(m_aSkinName);
+				}
+				lastSelectedSkin = m_nSelectedListRow;
+			} else if (!strcmp(m_PrefsSkinFile, m_pSelectedSkin->skinNameOriginal)) {
+				CFont::SetColor(CRGBA(255, 255, 155, FadeIn(255)));
+			} else {
+				CFont::SetColor(CRGBA(155, 155, 155, FadeIn(255)));
+			}
+			wchar unicodeTemp[80];
+			AsciiToUnicode(m_pSelectedSkin->skinNameDisplayed, unicodeTemp);
+			CFont::SetRightJustifyOff();
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(PLAYERSETUP_SKIN_COLUMN_LEFT), MENU_Y(rowTextY), unicodeTemp);
+
+			// If not "Default skin" option
+			if (rowIdx != 0) {
+				char dateTemp[32];
+				sprintf(dateTemp, "%s", m_pSelectedSkin->date);
+				AsciiToUnicode(dateTemp, unicodeTemp);
+				CFont::SetRightJustifyOn();
+				CFont::PrintString(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_DATE_COLUMN_RIGHT), MENU_Y(rowTextY), unicodeTemp);
+			}
+			++orderInVisibles;
+			rowEndY += PLAYERSETUP_ROW_HEIGHT;
+			rowStartY += PLAYERSETUP_ROW_HEIGHT;
+			rowTextY += PLAYERSETUP_ROW_HEIGHT;
+			++rowIdx;
+			m_pSelectedSkin = m_pSelectedSkin->nextSkin;
+		}
+		// Scrollbar background
+		CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2), MENU_Y(PLAYERSETUP_LIST_TOP),
+			MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2 - PLAYERSETUP_SCROLLBAR_WIDTH), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM)), CRGBA(100, 100, 66, FadeIn(205)));
+		
+		// Scrollbar
+		float scrollbarHeight = SCROLLBAR_MAX_HEIGHT / m_nSkinsTotal * (float) MAX_VISIBLE_LIST_ROW;
+		float scrollbarBottom, scrollbarTop;
+		if (m_nSkinsTotal <= MAX_VISIBLE_LIST_ROW) {
+			scrollbarBottom = SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 4.0f);
+			scrollbarTop = MENU_Y(PLAYERSETUP_LIST_BODY_TOP);
+
+			// Shadow
+			CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 4), scrollbarTop,
+				MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 1 - PLAYERSETUP_SCROLLBAR_WIDTH), scrollbarBottom + MENU_Y(1.0f)), CRGBA(50, 50, 50, FadeIn(255)));
+		} else {
+#ifdef FIX_BUGS
+			scrollbarBottom = MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 8 + m_nScrollbarTopMargin + scrollbarHeight);
+			scrollbarTop = MENU_Y(PLAYERSETUP_LIST_BODY_TOP + m_nScrollbarTopMargin);
+#else
+			scrollbarBottom = MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 4 + m_nScrollbarTopMargin + scrollbarHeight - SCROLLBAR_MAX_HEIGHT / m_nSkinsTotal);
+			scrollbarTop = MENU_Y(SCROLLBAR_MAX_HEIGHT / m_nSkinsTotal + PLAYERSETUP_LIST_BODY_TOP - 3 + m_nScrollbarTopMargin);
+#endif
+			// Shadow
+			CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 4), scrollbarTop,
+				MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 1 - PLAYERSETUP_SCROLLBAR_WIDTH), scrollbarBottom + MENU_Y(1.0f)),
+				CRGBA(50, 50, 50, FadeIn(255)));
+
+		}
+		CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 4), scrollbarTop,
+			MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - PLAYERSETUP_SCROLLBAR_WIDTH), scrollbarBottom),
+			CRGBA(235, 170, 50, FadeIn(255)));
+
+		// FIX: Scroll button dimensions are buggy, because:
+		//		1 - stretches the original image
+		//		2 - leaves gap between button and scrollbar
+		if (m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_UP) {
+#ifdef FIX_BUGS
+			m_aMenuSprites[MENUSPRITE_UPON].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2), MENU_Y(PLAYERSETUP_LIST_TOP),
+				MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2 - PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION), MENU_Y(PLAYERSETUP_LIST_TOP + PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION)),
+				CRGBA(255, 255, 255, FadeIn(255)));
+#else
+			m_aMenuSprites[MENUSPRITE_UPON].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2), MENU_Y(PLAYERSETUP_LIST_TOP),
+				MENU_X_RIGHT_ALIGNED(-20.0f), MENU_Y(PLAYERSETUP_LIST_TOP + 58)),
+				CRGBA(255, 255, 255, FadeIn(255)));
+#endif
+		} else {
+#ifdef FIX_BUGS
+			m_aMenuSprites[MENUSPRITE_UPOFF].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 3), MENU_Y(PLAYERSETUP_LIST_TOP),
+				MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 3 - PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION), MENU_Y(PLAYERSETUP_LIST_TOP + PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION)),
+				CRGBA(255, 255, 255, FadeIn(255)));
+#else
+			m_aMenuSprites[MENUSPRITE_UPOFF].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 3), MENU_Y(PLAYERSETUP_LIST_TOP),
+				MENU_X_RIGHT_ALIGNED(-21.0f), MENU_Y(PLAYERSETUP_LIST_TOP + 58)),
+				CRGBA(255, 255, 255, FadeIn(255)));
+#endif
+		}
+
+		if (m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_DOWN) {
+#ifdef FIX_BUGS
+			m_aMenuSprites[MENUSPRITE_DOWNON].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 1),
+				MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2 - PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 1 - PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION)),
+				CRGBA(255, 255, 255, FadeIn(255)));
+#else
+			m_aMenuSprites[MENUSPRITE_DOWNON].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2), SCREEN_SCALE_FROM_BOTTOM(141.0f),
+					MENU_X_RIGHT_ALIGNED(-20.0f), SCREEN_SCALE_FROM_BOTTOM(83.0f)),
+				CRGBA(255, 255, 255, FadeIn(255)));
+#endif
+		} else {
+#ifdef FIX_BUGS
+			m_aMenuSprites[MENUSPRITE_DOWNOFF].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 3), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 1),
+				MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 3 - PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 1 - PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION)),
+				CRGBA(255, 255, 255, FadeIn(255)));
+#else
+			m_aMenuSprites[MENUSPRITE_DOWNOFF].Draw(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 3), SCREEN_SCALE_FROM_BOTTOM(141.0f),
+				MENU_X_RIGHT_ALIGNED(-21.0f), SCREEN_SCALE_FROM_BOTTOM(83.0f)),
+				CRGBA(255, 255, 255, FadeIn(255)));
 #endif
 
-#if 0
-WRAPPER int CMenuManager::FadeIn(int alpha) { EAXJMP(0x48AC60); }
+		}
+		CPlayerSkin::RenderFrontendSkinEdit();
+
+		// Big apply button
+		if (strcmp(m_aSkinName, m_PrefsSkinFile) != 0) {
+			CFont::SetFontStyle(FONT_HEADING);
+			switch (m_PrefsLanguage) {
+				case LANGUAGE_FRENCH:
+					CFont::SetScale(MENU_X(1.1f), MENU_Y(1.9f));
+					break;
+				case LANGUAGE_GERMAN:
+					CFont::SetScale(MENU_X(0.85f), MENU_Y(1.9f));
+					break;
+				case LANGUAGE_ITALIAN:
+				case LANGUAGE_SPANISH:
+					CFont::SetScale(MENU_X(1.4f), MENU_Y(1.9f));
+					break;
+				default:
+					CFont::SetScale(MENU_X(1.9f), MENU_Y(1.9f));
+					break;
+			}
+			CFont::SetColor(CRGBA(255, 217, 106, FadeIn(120)));
+			CFont::SetRightJustifyOff();
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(20.0f), MENU_Y(220.0f), TheText.Get("FET_APL"));
+		}
+		CFont::SetFontStyle(FONT_HEADING);
+
+		CFont::SetScale(MENU_X(SMALLTEXT_X_SCALE), MENU_Y(SMALLTEXT_Y_SCALE));
+
+		if ((m_nMousePosX > MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 1) - CFont::GetStringWidth(TheText.Get("FEDS_TB"), true)
+			&& m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 1)
+			&& m_nMousePosY > SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM - 3)
+			&& m_nMousePosY < SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM - 26))
+			|| m_nCurrExLayer == HOVEROPTION_BACK) {
+			if (m_nHoverOption != HOVEROPTION_BACK)
+				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+			m_nHoverOption = HOVEROPTION_BACK;
+
+		} else if ((strcmp(m_aSkinName, m_PrefsSkinFile) != 0
+			&& m_nMousePosX > MENU_X_LEFT_ALIGNED(PLAYERSETUP_LIST_LEFT)
+			&& m_nMousePosX < MENU_X_LEFT_ALIGNED(PLAYERSETUP_LIST_LEFT) + CFont::GetStringWidth(TheText.Get("FES_SET"), true)
+			&& m_nMousePosY > SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM - 3)
+			&& m_nMousePosY < SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM - 26))
+			|| m_nCurrExLayer == HOVEROPTION_USESKIN) {
+			if (m_nHoverOption != HOVEROPTION_USESKIN)
+				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+			m_nHoverOption = HOVEROPTION_USESKIN;
+
+		} else if (m_nMousePosX > MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2)
+			&& m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - PLAYERSETUP_SCROLLBAR_WIDTH - 2)
+			&& m_nMousePosY > MENU_Y(PLAYERSETUP_LIST_TOP)
+			&& m_nMousePosY < MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 3)) {
+			if (m_nHoverOption != HOVEROPTION_CLICKED_SCROLL_UP && m_nHoverOption != HOVEROPTION_CLICKED_SCROLL_DOWN)
+				m_nHoverOption = HOVEROPTION_OVER_SCROLL_UP;
+
+		} else if (m_nMousePosX > MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2)
+			&& m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - PLAYERSETUP_SCROLLBAR_WIDTH - 2)
+			&& m_nMousePosY > SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 1)
+			&& m_nMousePosY < SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM)) {
+			if (m_nHoverOption != HOVEROPTION_CLICKED_SCROLL_UP && m_nHoverOption != HOVEROPTION_CLICKED_SCROLL_DOWN)
+				m_nHoverOption = HOVEROPTION_OVER_SCROLL_DOWN;
+
+		} else if (m_nMousePosX > MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2)
+			&& m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - PLAYERSETUP_SCROLLBAR_WIDTH - 2)
+				&& m_nMousePosY > MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 3)
+#ifdef FIX_BUGS
+				&& m_nMousePosY < MENU_Y(PLAYERSETUP_LIST_BODY_TOP + m_nScrollbarTopMargin)) {
 #else
-int CMenuManager::FadeIn(int alpha)
+				&& m_nMousePosY < MENU_Y(SCROLLBAR_MAX_HEIGHT / m_nTotalListRow + PLAYERSETUP_LIST_BODY_TOP - 3 + m_nScrollbarTopMargin)) {
+#endif
+			m_nHoverOption = HOVEROPTION_PAGEUP;
+
+		} else if (m_nMousePosX > MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2)
+			&& m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - PLAYERSETUP_SCROLLBAR_WIDTH - 2)
+#ifdef FIX_BUGS
+			&& m_nMousePosY > MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 8 + m_nScrollbarTopMargin + scrollbarHeight)
+#else
+			&& m_nMousePosY > MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 3 + m_nScrollbarTopMargin + scrollbarHeight - SCROLLBAR_MAX_HEIGHT / m_nTotalListRow)
+#endif
+			&& m_nMousePosY < SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 1)) {
+			m_nHoverOption = HOVEROPTION_PAGEDOWN;
+
+		} else if (m_nMousePosX > MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 4)
+			&& m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - PLAYERSETUP_SCROLLBAR_WIDTH)
+#ifdef FIX_BUGS
+			&& m_nMousePosY > MENU_Y(PLAYERSETUP_LIST_BODY_TOP + m_nScrollbarTopMargin)
+			&& m_nMousePosY < MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 8 + m_nScrollbarTopMargin + scrollbarHeight)) {
+#else
+			&& m_nMousePosY > MENU_Y(SCROLLBAR_MAX_HEIGHT / m_nTotalListRow + PLAYERSETUP_LIST_BODY_TOP - 3 + m_nScrollbarTopMargin)
+			&& m_nMousePosY < MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 3 + m_nScrollbarTopMargin + scrollbarHeight - SCROLLBAR_MAX_HEIGHT / m_nTotalListRow)) {
+#endif
+			m_nHoverOption = HOVEROPTION_HOLDING_SCROLLBAR;
+
+		} else if (m_nMousePosX > MENU_X_LEFT_ALIGNED(PLAYERSETUP_LIST_LEFT) && m_nMousePosX < MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT)
+			&& m_nMousePosY > MENU_Y(PLAYERSETUP_LIST_BODY_TOP + 1) && m_nMousePosY < SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM)) {
+			m_nHoverOption = HOVEROPTION_LIST;
+
+		} else {
+			m_nHoverOption = HOVEROPTION_NOT_HOVERING;
+		}
+	}
+	CFont::SetFontStyle(FONT_HEADING);
+	CFont::SetScale(MENU_X(SMALLTEXT_X_SCALE), MENU_Y(SMALLTEXT_Y_SCALE));
+	CFont::SetRightJustifyOn();
+	CFont::SetColor(CRGBA(0, 0, 0, FadeIn(90)));
+
+	// Back button
+	for (int i = 0; i < 2; i++) {
+		CFont::PrintString(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 3 - i), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM - 5 - i), TheText.Get("FEDS_TB"));
+		if (m_nHoverOption == HOVEROPTION_BACK) {
+			CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
+		} else {
+			CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+		}
+	}
+	CFont::SetRightJustifyOff();
+	CFont::SetColor(CRGBA(0, 0, 0, FadeIn(90)));
+
+	// Use skin button
+	for (int i = 0; i < 2; i++) {
+		CFont::PrintString(MENU_X_LEFT_ALIGNED(i + PLAYERSETUP_LIST_LEFT), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM - 5 - i), TheText.Get("FES_SET"));
+		if (!strcmp(m_aSkinName, m_PrefsSkinFile)) {
+			CFont::SetColor(CRGBA(155, 117, 6, FadeIn(255)));
+		} else if (m_nHoverOption == HOVEROPTION_USESKIN) {
+			CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
+		} else {
+			CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+		}
+	}
+
+}
+
+int
+CMenuManager::FadeIn(int alpha)
 {
 	if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS ||
 		m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS ||
@@ -1701,27 +2827,57 @@ int CMenuManager::FadeIn(int alpha)
 
 	return min(m_nMenuFadeAlpha, alpha);
 }
-#endif
 
-#if 1
-WRAPPER void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &) { EAXJMP(0x4889C0); }
-#else
-void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &)
+void
+CMenuManager::FilterOutColorMarkersFromString(wchar *str, CRGBA &newColor)
 {
+	int newIdx = 0;
+	wchar copy[256], *c;
+	UnicodeStrcpy(copy, str);
 
+	for (c = copy; *c != '\0'; c++) {
+		if (*c == '~') {
+			c++;
+			switch (*c) {
+				case 'b': newColor = CRGBA(40, 40, 255, 255); break;
+				case 'g': newColor = CRGBA(40, 235, 40, 255); break;
+				// There is no case for "h", is that a mistake?
+				case 'l': newColor = CRGBA(0, 0, 0, 255); break;
+				case 'p': newColor = CRGBA(255, 0, 255, 255); break;
+				case 'r': newColor = CRGBA(255, 0, 0, 255); break;
+				case 'w': newColor = CRGBA(255, 255, 255, 255); break;
+				case 'y': newColor = CRGBA(255, 255, 0, 255); break;
+			}
+			while (*c != '~') c++;
+		} else {
+			str[newIdx++] = *c;
+		}
+	}
+	str[newIdx] = '\0';
 }
-#endif
 
-#if 1
-WRAPPER int CMenuManager::GetStartOptionsCntrlConfigScreens() { EAXJMP(0x489270); }
-#else
-int CMenuManager::GetStartOptionsCntrlConfigScreens()
+int
+CMenuManager::GetStartOptionsCntrlConfigScreens()
 {
-
+	int number = 0;
+	switch (m_nCurrScreen) {
+		case MENUPAGE_CONTROLLER_PC_OLD3:
+			number = 34;
+			break;
+		case MENUPAGE_CONTROLLER_DEBUG:
+			number = 35;
+			break;
+		case MENUPAGE_KEYBOARD_CONTROLS:
+			number = 0;
+			break;
+		default:
+			break;
+	}
+	return number;
 }
-#endif
 
-void CMenuManager::InitialiseChangedLanguageSettings()
+void
+CMenuManager::InitialiseChangedLanguageSettings()
 {
 	if (m_bFrontEnd_ReloadObrTxtGxt) {
 		m_bFrontEnd_ReloadObrTxtGxt = false;
@@ -1732,7 +2888,7 @@ void CMenuManager::InitialiseChangedLanguageSettings()
 		CGame::frenchGame = false;
 		CGame::germanGame = false;
 #ifdef MORE_LANGUAGES
-		switch (CMenuManager::m_PrefsLanguage) {
+		switch (m_PrefsLanguage) {
 		case LANGUAGE_RUSSIAN:
 			CFont::ReloadFonts(FONT_LANGSET_RUSSIAN);
 			break;
@@ -1745,7 +2901,7 @@ void CMenuManager::InitialiseChangedLanguageSettings()
 		}
 #endif
 
-		switch (CMenuManager::m_PrefsLanguage) {
+		switch (m_PrefsLanguage) {
 		case LANGUAGE_FRENCH:
 			CGame::frenchGame = true;
 			break;
@@ -1763,22 +2919,23 @@ void CMenuManager::InitialiseChangedLanguageSettings()
 	}
 }
 
-void CMenuManager::LoadAllTextures()
+void
+CMenuManager::LoadAllTextures()
 {
 	if (m_bSpritesLoaded)
 		return;
 
-	CMenuManager::CentreMousePointer();
+	CentreMousePointer();
 	DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND);
 	DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0);
 	m_nCurrOption = 0;
 	m_PrefsRadioStation = DMAudio.GetRadioInCar();
 
 	if (DMAudio.IsMP3RadioChannelAvailable()) {
-		if (CMenuManager::m_PrefsRadioStation > USERTRACK)
-			CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10;
-	} else if (CMenuManager::m_PrefsRadioStation > CHATTERBOX)
-		CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9;
+		if (m_PrefsRadioStation > USERTRACK)
+			m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10;
+	} else if (m_PrefsRadioStation > CHATTERBOX)
+		m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9;
 	
 	CFileMgr::SetDir("");
 	//CFileMgr::SetDir("");
@@ -1818,14 +2975,18 @@ void CMenuManager::LoadAllTextures()
 		m_aMenuSprites[i].SetTexture(MenuFilenames[i][0], MenuFilenames[i][1]);
 		m_aMenuSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER);
 	}
-
+#ifdef MENU_MAP
+	for (int i = 0; i < ARRAY_SIZE(MapFilenames); i++) {
+		m_aMapSprites[i].SetTexture(MapFilenames[i][0], MapFilenames[i][1]);
+		m_aMapSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER);
+	}
+#endif
 	m_bSpritesLoaded = true;
 	CTxdStore::PopCurrentTxd();
 }
-#if 0
-WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); }
-#else
-void CMenuManager::LoadSettings()
+
+void
+CMenuManager::LoadSettings()
 {
 	CFileMgr::SetDirMyDocuments();
 	int fileHandle = CFileMgr::OpenFile("gta3.set", "r");
@@ -1914,12 +3075,9 @@ void CMenuManager::LoadSettings()
 		strcpy(m_aSkinName, "$$\"\"");
 	}
 }
-#endif
 
-#if 0
-WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); }
-#else
-void CMenuManager::SaveSettings()
+void
+CMenuManager::SaveSettings()
 {
 	static char RubbishString[48] = "stuffmorestuffevenmorestuff                 etc";
 
@@ -1962,44 +3120,117 @@ void CMenuManager::SaveSettings()
 	CFileMgr::CloseFile(fileHandle);
 	CFileMgr::SetDir("");
 }
-#endif
 
-#if 1
-WRAPPER void CMenuManager::MessageScreen(char *) { EAXJMP(0x48B7E0); }
-#else
-void CMenuManager::MessageScreen(char *)
+bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
+void DoRWStuffEndOfFrame(void);
+
+void
+CMenuManager::MessageScreen(const char *text)
 {
+	CSprite2d *splash = LoadSplash(nil);
+	if (!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
+		return;
 
+	CSprite2d::SetRecipNearClip();
+	CSprite2d::InitPerFrame();
+	CFont::InitPerFrame();
+	DefinedState();
+
+	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+	splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
+
+	CFont::SetBackgroundOff();
+	CFont::SetPropOn();
+	CFont::SetJustifyOn();
+	CFont::SetBackGroundOnlyTextOn();
+	CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(170.0f));
+	CFont::SetRightJustifyWrap(SCREEN_SCALE_FROM_RIGHT(170.0f));
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(120.0f), SCREEN_SCALE_Y(150.0f), SCREEN_SCALE_FROM_RIGHT(120.0f), SCREEN_SCALE_FROM_BOTTOM(220.0f)), CRGBA(50, 50, 50, 210));
+	CFont::SetFontStyle(FONT_BANK);
+	CFont::SetCentreSize(SCREEN_SCALE_X(380.0f));
+	CFont::SetCentreOn();
+	CFont::SetColor(CRGBA(255, 217, 106, 255));
+	CFont::SetScale(SCREEN_SCALE_X(SMALLTEXT_X_SCALE), SCREEN_SCALE_Y(SMALLTEXT_Y_SCALE));
+	CFont::PrintString(SCREEN_SCALE_X(320.0f), SCREEN_SCALE_Y(170.0f), TheText.Get(text));
+	CFont::DrawFonts();
+	DoRWStuffEndOfFrame();
 }
-#endif
 
-#if 1
-WRAPPER void CMenuManager::PickNewPlayerColour() { EAXJMP(0x488C40); }
-#else
-void CMenuManager::PickNewPlayerColour()
+void
+CMenuManager::PickNewPlayerColour()
 {
-
+	m_PrefsPlayerRed = 0;
+	m_PrefsPlayerGreen = 0;
+	m_PrefsPlayerBlue = 0;
+	while (true) {
+		int sum = m_PrefsPlayerRed + m_PrefsPlayerGreen + m_PrefsPlayerBlue;
+		if (sum >= 100 && sum <= 650)
+			break;
+		m_PrefsPlayerRed = CGeneral::GetRandomNumber();
+		m_PrefsPlayerGreen = CGeneral::GetRandomNumber();
+		m_PrefsPlayerBlue = CGeneral::GetRandomNumber();
+	}
 }
-#endif
 
-#if 1
-WRAPPER void CMenuManager::PrintBriefs() { EAXJMP(0x484D60); }
-#else
-void CMenuManager::PrintBriefs()
+void
+CMenuManager::PrintBriefs()
 {
+	CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+	CFont::SetFontStyle(FONT_BANK);
+	CFont::SetRightJustifyOff();
+	CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X * 0.7), MENU_Y(MENU_TEXT_SIZE_Y * 0.9)); // second mulipliers are double, idk why
 
-}
+	float nextY = 40.0f;
+	CRGBA newColor;
+	for (int i = 4; i >= 0; i--) {
+		tPreviousBrief &brief = CMessages::PreviousBriefs[i];
+		if (brief.m_pText) {
+			CMessages::InsertNumberInString(brief.m_pText,
+				brief.m_nNumber[0], brief.m_nNumber[1],
+				brief.m_nNumber[2], brief.m_nNumber[3],
+				brief.m_nNumber[4], brief.m_nNumber[5], gUString);
+			CMessages::InsertStringInString(gUString, brief.m_pString);
+			CMessages::InsertPlayerControlKeysInString(gUString);
+			newColor = TEXT_COLOR;
+			FilterOutColorMarkersFromString(gUString, newColor);
+
+#ifdef PS2_LIKE_MENU
+			// This PS2 code was always here, but unused
+			bool rgSame = newColor.r == TEXT_COLOR.r && newColor.g == TEXT_COLOR.g;
+			bool bSame = rgSame && newColor.b == TEXT_COLOR.b;
+			bool colorNotChanged = bSame; /* && newColor.a == TEXT_COLOR.a; */
+
+			if (!colorNotChanged) {
+				newColor.r /= 2;
+				newColor.g /= 2;
+				newColor.b /= 2;
+			}
+			CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(255))); // But this is from PS2
+			CFont::SetDropShadowPosition(1);
 #endif
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::PrintErrorMessage() { EAXJMP(0x484F70); }
-#else
-void CMenuManager::PrintErrorMessage()
+#if defined(FIX_BUGS) || defined(PS2_LIKE_MENU)
+			newColor.a = FadeIn(255);
+			CFont::SetColor(newColor);
+#endif
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(50.0f), nextY, gUString);
+			nextY += MENU_Y(menuXYpadding);
+		}
+	}
+
+#ifdef PS2_LIKE_MENU
+	CFont::SetDropShadowPosition(0);
+#endif
+}
+
+// Not sure about name. Not to be confused with CPad::PrintErrorMessage
+void
+CMenuManager::PrintErrorMessage()
 {
 	if (!CPad::bDisplayNoControllerMessage && !CPad::bObsoleteControllerMessage)
 		return;
 
-	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(20.0f), SCREEN_SCALE_Y(140.0f), SCREEN_WIDTH - SCREEN_SCALE_X(20.0f), SCREEN_HEIGHT - SCREEN_SCALE_Y(140.0f)), CRGBA(64, 16, 16, 224));
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(20.0f), SCREEN_SCALE_Y(140.0f), SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(120.0f)), CRGBA(64, 16, 16, 224));
 	CFont::SetFontStyle(FONT_BANK);
 	CFont::SetBackgroundOff();
 	CFont::SetPropOn();
@@ -2007,36 +3238,106 @@ void CMenuManager::PrintErrorMessage()
 	CFont::SetJustifyOn();
 	CFont::SetRightJustifyOff();
 	CFont::SetBackGroundOnlyTextOn();
-	CFont::SetWrapx(SCREEN_WIDTH - 40.0f);
-	CFont::SetColor(CRGBA(165, 165, 165, 255));
-	CFont::SetScale(SCREEN_SCALE_X(0.9f), SCREEN_SCALE_Y(0.9f));
-	CFont::PrintString(SCREEN_SCALE_X(40.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(60.0f), TheText.Get(CPad::bDisplayNoControllerMessage ? "NOCONT" : "WRCONT"));
+	CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(40.0f));
+#ifdef FIX_BUGS
+	CFont::PrintString(SCREEN_SCALE_X(50.0f), SCREEN_SCALE_Y(180.0f), TheText.Get(CPad::bDisplayNoControllerMessage ? "NOCONT" : "WRCONT"));
+#else
+	CFont::PrintString(SCREEN_SCALE_X(50.0f), SCREEN_SCALE_Y(40.0f), TheText.Get(CPad::bDisplayNoControllerMessage ? "NOCONT" : "WRCONT"));
+#endif
 	CFont::DrawFonts();
 }
-#endif
 
-#if 1
-WRAPPER void CMenuManager::PrintStats() { EAXJMP(0x482100); }
-#else
-void CMenuManager::PrintStats()
+void
+CMenuManager::PrintStats()
 {
+	int rowNum = ConstructStatLine(99999);
+	CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X * 0.7), MENU_Y(MENU_TEXT_SIZE_Y * 0.9)); // second mulipliers are double, idk why
+	float nextYChange, y, alphaMult;
 
-}
+	// Scroll stats with mouse
+#ifdef SCROLLABLE_STATS_PAGE
+	static float scrollY = 0;
+	static uint32 lastChange = m_nScreenChangeDelayTimer;
+	if (CPad::GetPad(0)->GetLeftMouse()) {
+		scrollY += (m_nMouseOldPosY - m_nMousePosY);
+		lastChange = CTimer::GetTimeInMillisecondsPauseMode();
+	} else {
+		scrollY += MENU_Y(STATS_SLIDE_Y_PER_SECOND) / 1000.0f * (CTimer::GetTimeInMillisecondsPauseMode() - lastChange);
+		lastChange = CTimer::GetTimeInMillisecondsPauseMode();
+	}
+#else
+	// MENU_Y(30.0f) per second
+	float scrollY = MENU_Y(STATS_SLIDE_Y_PER_SECOND) * (CTimer::GetTimeInMillisecondsPauseMode() - m_nScreenChangeDelayTimer) / 1000.0f;
 #endif
 
-#if 0
-WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); }
-#else
-void CMenuManager::Process(void)
+	for (int row = 0; row < rowNum; ++row) {
+		// Put just got hidden text at the top back to the bottom, in circular fashion
+		for (y = MENU_Y(STATS_ROW_HEIGHT - 1) * row + SCREEN_HEIGHT - scrollY; MENU_Y(STATS_PUT_BACK_TO_BOTTOM_Y) > y; y += nextYChange) {
+			nextYChange = (MENU_Y(STATS_ROW_HEIGHT) + rowNum) * MENU_Y(STATS_ROW_HEIGHT - 1);
+		}
+
+		// If it's still on screen
+		if (y > 0.0f && SCREEN_HEIGHT > y) {
+			ConstructStatLine(row);
+
+			// But about to dim from top
+			if (y - MENU_Y(STATS_BOTTOM_MARGIN) < MENU_Y(STATS_TOP_DIMMING_AREA_LENGTH)) {
+				if ((y - MENU_Y(STATS_BOTTOM_MARGIN)) / MENU_Y(STATS_TOP_DIMMING_AREA_LENGTH) < 0.0f)
+					alphaMult = 0.0f;
+				else
+					alphaMult = (y - MENU_Y(STATS_BOTTOM_MARGIN)) / MENU_Y(STATS_TOP_DIMMING_AREA_LENGTH);
+
+			// About to dim from bottom
+			} else if (y > SCREEN_SCALE_FROM_BOTTOM(STATS_TOP_DIMMING_AREA_LENGTH) - MENU_Y(STATS_BOTTOM_DIMMING_AREA_LENGTH)) {
+				if ((SCREEN_SCALE_FROM_BOTTOM(STATS_BOTTOM_DIMMING_AREA_LENGTH) - y) / MENU_Y(STATS_TOP_DIMMING_AREA_LENGTH) < 0.0f)
+					alphaMult = 0.0f;
+				else
+					alphaMult = (SCREEN_SCALE_FROM_BOTTOM(STATS_BOTTOM_DIMMING_AREA_LENGTH) - y) / MENU_Y(STATS_TOP_DIMMING_AREA_LENGTH);
+			} else
+				alphaMult = 1.0f;
+
+			CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255.0f * alphaMult)));
+			CFont::SetRightJustifyOff();
+			CFont::PrintString(MENU_X_LEFT_ALIGNED(STATS_ROW_X_MARGIN), y - MENU_Y(STATS_BOTTOM_MARGIN - STATS_TOP_MARGIN), gUString);
+			CFont::SetRightJustifyOn();
+			CFont::PrintString(MENU_X_RIGHT_ALIGNED(STATS_ROW_X_MARGIN), y - MENU_Y(STATS_BOTTOM_MARGIN - STATS_TOP_MARGIN), gUString2);
+		}
+	}
+	// Game doesn't do that, but it's better
+	float nextX = MENU_X_LEFT_ALIGNED(STATS_RATING_X);
+
+	CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+	CFont::SetRightJustifyOff();
+	CFont::PrintString(nextX, MENU_Y(STATS_RATING_Y), TheText.Get("CRIMRA")); nextX += MENU_X(10.0f) + CFont::GetStringWidth(TheText.Get("CRIMRA"), true);
+	UnicodeStrcpy(gUString, CStats::FindCriminalRatingString());
+	CFont::PrintString(nextX, MENU_Y(STATS_RATING_Y), gUString); nextX += MENU_X(6.0f) + CFont::GetStringWidth(gUString, true);
+	sprintf(gString, "%d", CStats::FindCriminalRatingNumber());
+	AsciiToUnicode(gString, gUString);
+	CFont::PrintString(nextX, MENU_Y(STATS_RATING_Y), gUString);
+
+	// ::Draw already does that.
+	/*
+	CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
+	CFont::SetRightJustifyOn();
+	CFont::SetFontStyle(FONT_HEADING);
+	CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT));
+	CFont::PrintString(MENU_X_RIGHT_ALIGNED(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName));
+	*/
+	CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X), MENU_Y(MENU_TEXT_SIZE_Y));
+}
+
+void
+CMenuManager::Process(void)
 {
 	m_bMenuStateChanged = false;
 
 	if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0)
 		return;
 
-	m_bStartGameLoading = false;
+	m_bWantToRestart = false;
 	InitialiseChangedLanguageSettings();
 
+	// Just a hack by R* to not make game continuously resume/pause. But we it seems we can live with it.
 	if (CPad::GetPad(0)->GetEscapeJustDown())
 		RequestFrontEndStartUp();
 
@@ -2076,9 +3377,9 @@ void CMenuManager::Process(void)
 				if (m_PrefsVsyncDisp != m_PrefsVsync)
 					m_PrefsVsync = m_PrefsVsyncDisp;
 				DMAudio.Service();
-				m_bStartGameLoading = true;
+				m_bWantToRestart = true;
 				RequestFrontEndShutDown();
-				m_bLoadingSavedGame = true;
+				m_bWantToLoad = true;
 				b_FoundRecentSavedGameWantToLoad = true;
 				DMAudio.SetEffectsFadeVol(0);
 				DMAudio.SetMusicFadeVol(0);
@@ -2103,8 +3404,8 @@ void CMenuManager::Process(void)
 				m_bStartWaitingForKeyBind = false;
 			else {
 				pControlEdit = CPad::EditCodesForControls(pControlEdit, 1);
-				JoyButtonJustClicked = 0;
-				MouseButtonJustClicked = 0;
+				JoyButtonJustClicked = false;
+				MouseButtonJustClicked = false;
 
 				if (CPad::GetPad(0)->GetLeftMouseJustDown())
 					MouseButtonJustClicked = 1;
@@ -2120,13 +3421,13 @@ void CMenuManager::Process(void)
 
 				JoyButtonJustClicked = ControlsManager.GetJoyButtonJustDown();
 
-				int32 TypeOfControl = 0;
+				int32 TypeOfControl = KEYBOARD;
 				if (JoyButtonJustClicked)
-					TypeOfControl = 3;
+					TypeOfControl = JOYSTICK;
 				if (MouseButtonJustClicked)
-					TypeOfControl = 2;
+					TypeOfControl = MOUSE;
 				if (*pControlEdit != rsNULL)
-					TypeOfControl = 0;
+					TypeOfControl = KEYBOARD;
 
 				if (!m_bKeyIsOK) {
 					DMAudio.PlayFrontEndSound(SOUND_FRONTEND_FAIL, 0);
@@ -2134,14 +3435,12 @@ void CMenuManager::Process(void)
 					m_bWaitingForNewKeyBind = false;
 					m_KeyPressedCode = -1;
 					m_bStartWaitingForKeyBind = false;
-				}
-				else if (!m_bKeyChangeNotProcessed) {
+				} else if (!m_bKeyChangeNotProcessed) {
 					if (*pControlEdit != rsNULL || MouseButtonJustClicked || JoyButtonJustClicked)
 						CheckCodesForControls(TypeOfControl);
 
 					field_535 = true;
-				}
-				else {
+				} else {
 					DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
 					for (int i = 0; i < 4; i++)
 						ControlsManager.ClearSettingsAssociatedWithAction((e_ControllerAction)m_CurrCntrlAction, (eControllerType)i);
@@ -2155,7 +3454,7 @@ void CMenuManager::Process(void)
 			}
 		}
 
-		if ((m_nCurrScreen == MENUPAGE_13 || m_nCurrScreen == MENUPAGE_16) && CTimer::GetTimeInMillisecondsPauseMode() > field_558) {
+		if ((m_nCurrScreen == MENUPAGE_NO_MEMORY_CARD || m_nCurrScreen == MENUPAGE_PS2_LOAD_FAILED) && CTimer::GetTimeInMillisecondsPauseMode() > field_558) {
 			m_nCurrScreen = m_nPrevScreen;
 			m_nCurrOption = 0;
 		}
@@ -2175,16 +3474,12 @@ void CMenuManager::Process(void)
 		m_bWaitingForNewKeyBind = false;
 	}
 
-	if (!m_bStartGameLoading) {
+	if (!m_bWantToRestart) {
 		if (m_bGameNotLoaded)
 			DMAudio.Service();
 	}
 }
-#endif
 
-#if 0
-WRAPPER void CMenuManager::ProcessButtonPresses() { EAXJMP(0x4856F0); }
-#else
 void
 CMenuManager::ProcessButtonPresses(void)
 {
@@ -2232,7 +3527,7 @@ CMenuManager::ProcessButtonPresses(void)
 		}
 #endif
 		if (CPad::GetPad(0)->GetBackspaceJustDown() && m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS && !field_535) {
-			if (m_nCurrExLayer == 19) {
+			if (m_nCurrExLayer == HOVEROPTION_LIST) {
 				m_nHoverOption = HOVEROPTION_NOT_HOVERING;
 				m_bWaitingForNewKeyBind = true;
 				m_bStartWaitingForKeyBind = true;
@@ -2258,21 +3553,21 @@ CMenuManager::ProcessButtonPresses(void)
 			DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
 			m_bShowMouse = false;
 			switch (m_nCurrExLayer) {
-				case 9:
+				case HOVEROPTION_BACK:
 				default:
-					m_nCurrExLayer = 19;
+					m_nCurrExLayer = HOVEROPTION_LIST;
 					break;
-				case 19:
-					m_nCurrExLayer = 21;
+				case HOVEROPTION_LIST:
+					m_nCurrExLayer = HOVEROPTION_USESKIN;
 					break;
-				case 21:
-					m_nCurrExLayer = 9;
+				case HOVEROPTION_USESKIN:
+					m_nCurrExLayer = HOVEROPTION_BACK;
 			}
-			if (((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && (m_nCurrExLayer == 21)) && strcmp(m_aSkinName, m_PrefsSkinFile) == 0) {
-				m_nCurrExLayer = 9;
+			if (((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) && strcmp(m_aSkinName, m_PrefsSkinFile) == 0) {
+				m_nCurrExLayer = HOVEROPTION_BACK;
 			}
-			if ((m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) && (m_nCurrExLayer == 21)) {
-				m_nCurrExLayer = 9;
+			if ((m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) {
+				m_nCurrExLayer = HOVEROPTION_BACK;
 			}
 		}
 
@@ -2287,7 +3582,7 @@ CMenuManager::ProcessButtonPresses(void)
 
 		// Up
 		if (pressed) {
-			m_nCurrExLayer = 19;
+			m_nCurrExLayer = HOVEROPTION_LIST;
 			if (!m_bPressedUpOnList) {
 				m_bPressedUpOnList = true;
 				lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
@@ -2309,7 +3604,7 @@ CMenuManager::ProcessButtonPresses(void)
 
 		// Down
 		if (pressed) {
-			m_nCurrExLayer = 19;
+			m_nCurrExLayer = HOVEROPTION_LIST;
 			if (!m_bPressedDownOnList) {
 				m_bPressedDownOnList = true;
 				lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
@@ -2324,7 +3619,7 @@ CMenuManager::ProcessButtonPresses(void)
 			if (!CPad::GetPad(0)->GetPageUp()) {
 				m_bPressedPgUpOnList = false;
 			} else {
-				m_nCurrExLayer = 19;
+				m_nCurrExLayer = HOVEROPTION_LIST;
 				if (!m_bPressedPgUpOnList) {
 					m_bPressedPgUpOnList = true;
 					lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
@@ -2336,7 +3631,7 @@ CMenuManager::ProcessButtonPresses(void)
 			if (!CPad::GetPad(0)->GetPageDown()) {
 				m_bPressedPgDnOnList = false;
 			} else {
-				m_nCurrExLayer = 19;
+				m_nCurrExLayer = HOVEROPTION_LIST;
 				if (!m_bPressedPgDnOnList) {
 					m_bPressedPgDnOnList = true;
 					lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode();
@@ -2346,29 +3641,29 @@ CMenuManager::ProcessButtonPresses(void)
 				}
 			}
 			if (CPad::GetPad(0)->GetHome()) {
-				m_nCurrExLayer = 19;
+				m_nCurrExLayer = HOVEROPTION_LIST;
 				m_bShowMouse = false;
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
 				if (m_nTotalListRow >= MAX_VISIBLE_LIST_ROW) {
 					m_nFirstVisibleRowOnList = 0;
 				}
 				m_nSelectedListRow = 0;
-				m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+				m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
 			}
 			if (CPad::GetPad(0)->GetEnd()) {
-				m_nCurrExLayer = 19;
+				m_nCurrExLayer = HOVEROPTION_LIST;
 				m_bShowMouse = false;
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
 				if (m_nTotalListRow >= MAX_VISIBLE_LIST_ROW) {
 					m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW;
 				}
 				m_nSelectedListRow = m_nTotalListRow - 1;
-				m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+				m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
 			}
 		}
 
 #ifndef TIDY_UP_PBP
-		if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetSquareJustDown()) {
+		if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetBackJustDown()) {
 			m_bShowMouse = false;
 			goBack = true;
 		}
@@ -2385,10 +3680,10 @@ CMenuManager::ProcessButtonPresses(void)
 				case HOVEROPTION_PAGEDOWN:
 					PageDownList(true);
 					break;
-				case HOVEROPTION_CHANGESKIN:
+				case HOVEROPTION_USESKIN:
 					if (m_nSkinsTotal > 0) {
 						DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-						m_pSelectedSkin = m_sSkin.field_304;
+						m_pSelectedSkin = m_pSkinListHead.nextSkin;
 						strcpy(m_PrefsSkinFile, m_aSkinName);
 						CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
 						SaveSettings();
@@ -2404,8 +3699,8 @@ CMenuManager::ProcessButtonPresses(void)
 				case HOVEROPTION_OVER_SCROLL_DOWN:
 					m_nHoverOption = HOVEROPTION_CLICKED_SCROLL_DOWN;
 					break;
-				case HOVEROPTION_19:
-					m_nHoverOption = HOVEROPTION_20;
+				case HOVEROPTION_LIST:
+					m_nHoverOption = HOVEROPTION_SKIN;
 			}
 		} else if ((CPad::GetPad(0)->GetLeftMouseJustUp())
 			&& ((m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_UP || (m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_DOWN)))) {
@@ -2418,7 +3713,7 @@ CMenuManager::ProcessButtonPresses(void)
 			if ((m_nHoverOption == HOVEROPTION_HOLDING_SCROLLBAR) || holdingScrollBar) {
 				holdingScrollBar = true;
 				// TODO: This part is a bit hard to reverse. Not much code tho
-				assert(0 && "Not done yet");
+				assert(0 && "Holding scrollbar isn't done yet");
 			} else {
 				switch (m_nHoverOption) {
 				case HOVEROPTION_OVER_SCROLL_UP:
@@ -2447,7 +3742,7 @@ CMenuManager::ProcessButtonPresses(void)
 		if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown() || CPad::GetPad(0)->GetLeftMouseJustDown()) {
 			optionSelected = true;
 		}
-		if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetSquareJustUp()) {
+		if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetBackJustUp()) {
 			if (m_nCurrScreen != MENUPAGE_START_MENU) {
 				goBack = true;
 			}
@@ -2492,10 +3787,10 @@ CMenuManager::ProcessButtonPresses(void)
 #ifdef TIDY_UP_PBP
 			if (m_nHoverOption >= HOVEROPTION_RADIO_0 && m_nHoverOption <= HOVEROPTION_RADIO_9) {
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = m_nHoverOption - HOVEROPTION_RADIO_0;
+				m_PrefsRadioStation = m_nHoverOption - HOVEROPTION_RADIO_0;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 			} else if (m_nHoverOption == HOVEROPTION_RANDOM_ITEM
 				&& aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action != MENUACTION_RESUME) {
@@ -2506,82 +3801,82 @@ CMenuManager::ProcessButtonPresses(void)
 			switch (m_nHoverOption) {
 			case HOVEROPTION_RADIO_0:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = HEAD_RADIO;
+				m_PrefsRadioStation = HEAD_RADIO;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_1:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = DOUBLE_CLEF;
+				m_PrefsRadioStation = DOUBLE_CLEF;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_2:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = JAH_RADIO;
+				m_PrefsRadioStation = JAH_RADIO;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_3:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = RISE_FM;
+				m_PrefsRadioStation = RISE_FM;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_4:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = LIPS_106;
+				m_PrefsRadioStation = LIPS_106;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_5:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = GAME_FM;
+				m_PrefsRadioStation = GAME_FM;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_6:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = MSX_FM;
+				m_PrefsRadioStation = MSX_FM;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_7:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = FLASHBACK;
+				m_PrefsRadioStation = FLASHBACK;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_8:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = CHATTERBOX;
+				m_PrefsRadioStation = CHATTERBOX;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RADIO_9:
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::m_PrefsRadioStation = USERTRACK;
+				m_PrefsRadioStation = USERTRACK;
 				SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case HOVEROPTION_RANDOM_ITEM:
@@ -2598,74 +3893,74 @@ CMenuManager::ProcessButtonPresses(void)
 #ifndef TIDY_UP_PBP
 			switch (m_nHoverOption) {
 			case HOVEROPTION_INCREASE_BRIGHTNESS:
-				CMenuManager::m_PrefsBrightness = CMenuManager::m_PrefsBrightness + 32;
-				if (CMenuManager::m_PrefsBrightness < 0) {
-					CMenuManager::m_PrefsBrightness = 0;
+				m_PrefsBrightness = m_PrefsBrightness + 32;
+				if (m_PrefsBrightness < 0) {
+					m_PrefsBrightness = 0;
 				}
-				if (510 < CMenuManager::m_PrefsBrightness) {
-					CMenuManager::m_PrefsBrightness = 511;
+				if (510 < m_PrefsBrightness) {
+					m_PrefsBrightness = 511;
 				}
 				SaveSettings();
 				break;
 			case HOVEROPTION_DECREASE_BRIGHTNESS:
-				CMenuManager::m_PrefsBrightness = CMenuManager::m_PrefsBrightness - 32;
-				if (CMenuManager::m_PrefsBrightness < 0) {
-					CMenuManager::m_PrefsBrightness = 0;
+				m_PrefsBrightness = m_PrefsBrightness - 32;
+				if (m_PrefsBrightness < 0) {
+					m_PrefsBrightness = 0;
 				}
-				if (510 < CMenuManager::m_PrefsBrightness) {
-					CMenuManager::m_PrefsBrightness = 511;
+				if (510 < m_PrefsBrightness) {
+					m_PrefsBrightness = 511;
 				}
 				SaveSettings();
 				break;
 			case HOVEROPTION_INCREASE_DRAWDIST:
-				CMenuManager::m_PrefsLOD = CMenuManager::m_PrefsLOD + (1.0f / 16);
+				m_PrefsLOD = m_PrefsLOD + (1.0f / 16);
 				m_PrefsLOD = min(1.8f, m_PrefsLOD);
-				CRenderer::ms_lodDistScale = CMenuManager::m_PrefsLOD;
+				CRenderer::ms_lodDistScale = m_PrefsLOD;
 				SaveSettings();
 				break;
 			case HOVEROPTION_DECREASE_DRAWDIST:
-				CMenuManager::m_PrefsLOD = CMenuManager::m_PrefsLOD - (1.0f / 16);
+				m_PrefsLOD = m_PrefsLOD - (1.0f / 16);
 				m_PrefsLOD = max(0.8f, m_PrefsLOD);
-				CRenderer::ms_lodDistScale = CMenuManager::m_PrefsLOD;
+				CRenderer::ms_lodDistScale = m_PrefsLOD;
 				SaveSettings();
 				break;
 			case HOVEROPTION_INCREASE_MUSICVOLUME:
-				CMenuManager::m_PrefsMusicVolume = CMenuManager::m_PrefsMusicVolume + 8;
+				m_PrefsMusicVolume = m_PrefsMusicVolume + 8;
 				m_PrefsMusicVolume = clamp(m_PrefsMusicVolume, 0, 127);
-				DMAudio.SetMusicMasterVolume(uchar)(CMenuManager::m_PrefsMusicVolume);
+				DMAudio.SetMusicMasterVolume(uchar)(m_PrefsMusicVolume);
 				SaveSettings();
 				break;
 			case HOVEROPTION_DECREASE_MUSICVOLUME:
-				CMenuManager::m_PrefsMusicVolume = CMenuManager::m_PrefsMusicVolume - 8;
-				if (CMenuManager::m_PrefsMusicVolume < 0) {
-					CMenuManager::m_PrefsMusicVolume = 0;
+				m_PrefsMusicVolume = m_PrefsMusicVolume - 8;
+				if (m_PrefsMusicVolume < 0) {
+					m_PrefsMusicVolume = 0;
 				}
-				if (126 < CMenuManager::m_PrefsMusicVolume) {
-					CMenuManager::m_PrefsMusicVolume = 127;
+				if (126 < m_PrefsMusicVolume) {
+					m_PrefsMusicVolume = 127;
 				}
-				DMAudio.SetMusicMasterVolume(uchar)(CMenuManager::m_PrefsMusicVolume);
+				DMAudio.SetMusicMasterVolume(uchar)(m_PrefsMusicVolume);
 				SaveSettings();
 				break;
 			case HOVEROPTION_INCREASE_SFXVOLUME:
-				CMenuManager::m_PrefsSFXVolume = CMenuManager::m_PrefsSFXVolume + 8;
-				if (CMenuManager::m_PrefsSFXVolume < 0) {
-					CMenuManager::m_PrefsSFXVolume = 0;
+				m_PrefsSFXVolume = m_PrefsSFXVolume + 8;
+				if (m_PrefsSFXVolume < 0) {
+					m_PrefsSFXVolume = 0;
 				}
-				if (126 < CMenuManager::m_PrefsSFXVolume) {
-					CMenuManager::m_PrefsSFXVolume = 127;
+				if (126 < m_PrefsSFXVolume) {
+					m_PrefsSFXVolume = 127;
 				}
-				DMAudio.SetEffectsMasterVolume(uchar)(CMenuManager::m_PrefsSFXVolume);
+				DMAudio.SetEffectsMasterVolume(uchar)(m_PrefsSFXVolume);
 				SaveSettings();
 				break;
 			case HOVEROPTION_DECREASE_SFXVOLUME:
-				CMenuManager::m_PrefsSFXVolume = CMenuManager::m_PrefsSFXVolume - 8;
-				if (CMenuManager::m_PrefsSFXVolume < 0) {
-					CMenuManager::m_PrefsSFXVolume = 0;
+				m_PrefsSFXVolume = m_PrefsSFXVolume - 8;
+				if (m_PrefsSFXVolume < 0) {
+					m_PrefsSFXVolume = 0;
 				}
-				if (126 < CMenuManager::m_PrefsSFXVolume) {
-					CMenuManager::m_PrefsSFXVolume = 127;
+				if (126 < m_PrefsSFXVolume) {
+					m_PrefsSFXVolume = 127;
 				}
-				DMAudio.SetEffectsMasterVolume(uchar)(CMenuManager::m_PrefsSFXVolume);
+				DMAudio.SetEffectsMasterVolume(uchar)(m_PrefsSFXVolume);
 				SaveSettings();
 				break;
 			case HOVEROPTION_INCREASE_MOUSESENS:
@@ -2715,7 +4010,7 @@ CMenuManager::ProcessButtonPresses(void)
 
 		}
 #ifndef TIDY_UP_PBP
-		if (CPad::GetPad(0)->GetSquareJustDown()) {
+		if (CPad::GetPad(0)->GetBackJustDown()) {
 			if (m_nCurrScreen != MENUPAGE_START_MENU && m_nCurrScreen != MENUPAGE_PAUSE_MENU) {
 				m_bShowMouse = false;
 				goBack = true;
@@ -2756,11 +4051,11 @@ CMenuManager::ProcessButtonPresses(void)
 	if (!goDown && !goUp && !optionSelected) {
 		if (m_nCurrScreen != MENUPAGE_START_MENU) {
 			if (isPlainTextScreen(m_nCurrScreen)) {
-				if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetSquareJustUp()) {
+				if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetBackJustUp()) {
 					goBack = true;
 				}
 			} else {
-				if (CPad::GetPad(0)->GetEscapeJustDown() || (m_nCurrScreen != MENUPAGE_PAUSE_MENU && CPad::GetPad(0)->GetSquareJustDown())) {
+				if (CPad::GetPad(0)->GetEscapeJustDown() || (m_nCurrScreen != MENUPAGE_PAUSE_MENU && CPad::GetPad(0)->GetBackJustDown())) {
 					m_bShowMouse = false;
 					goBack = true;
 				}
@@ -2869,7 +4164,7 @@ CMenuManager::ProcessButtonPresses(void)
 				default:
 					goBack = true;
 					break;
-				case 19:
+				case HOVEROPTION_LIST:
 					if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) {
 						m_bWaitingForNewKeyBind = true;
 						m_bStartWaitingForKeyBind = true;
@@ -2878,16 +4173,16 @@ CMenuManager::ProcessButtonPresses(void)
 					if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
 						strcpy(m_PrefsSkinFile, m_aSkinName);
 						CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
-						m_nCurrExLayer = 9;
-						CMenuManager::SaveSettings();
+						m_nCurrExLayer = HOVEROPTION_BACK;
+						SaveSettings();
 					}
 					m_nHoverOption = HOVEROPTION_NOT_HOVERING;
 					break;
-				case 21:
+				case HOVEROPTION_USESKIN:
 					m_nHoverOption = HOVEROPTION_NOT_HOVERING;
 					strcpy(m_PrefsSkinFile, m_aSkinName);
 					CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
-					m_nCurrExLayer = 9;
+					m_nCurrExLayer = HOVEROPTION_BACK;
 					SaveSettings();
 					break;
 			}
@@ -2898,7 +4193,7 @@ CMenuManager::ProcessButtonPresses(void)
 */
 		} else if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
 			if (m_nSkinsTotal > 0) {
-				m_pSelectedSkin = (tSkinInfo*)(m_sSkin).field_304;
+				m_pSelectedSkin = m_pSkinListHead.nextSkin;
 				strcpy(m_PrefsSkinFile, m_aSkinName);
 				CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
 				SaveSettings();
@@ -2915,47 +4210,47 @@ CMenuManager::ProcessButtonPresses(void)
 #ifdef TIDY_UP_PBP
 					assumeIncrease = true;
 #else
-					++CMenuManager::m_PrefsRadioStation;
-					if (cDMAudio::IsMP3RadioChannelAvailable()) {
-						if (CMenuManager::m_PrefsRadioStation > USERTRACK)
-							CMenuManager::m_PrefsRadioStation = HEAD_RADIO;
-					} else if (CMenuManager::m_PrefsRadioStation > CHATTERBOX) {
-						CMenuManager::m_PrefsRadioStation = USERTRACK;
+					++m_PrefsRadioStation;
+					if (DMAudio.IsMP3RadioChannelAvailable()) {
+						if (m_PrefsRadioStation > USERTRACK)
+							m_PrefsRadioStation = HEAD_RADIO;
+					} else if (m_PrefsRadioStation > CHATTERBOX) {
+						m_PrefsRadioStation = USERTRACK;
 					}
 					SaveSettings();
-					DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-					DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+					DMAudio.SetRadioInCar(m_PrefsRadioStation);
+					DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 					OutputDebugString("FRONTEND RADIO STATION CHANGED");
 #endif
 					break;
 				case MENUACTION_LANG_ENG:
 					m_PrefsLanguage = LANGUAGE_AMERICAN;
 					m_bFrontEnd_ReloadObrTxtGxt = true;
-					CMenuManager::InitialiseChangedLanguageSettings();
-					CMenuManager::SaveSettings();
+					InitialiseChangedLanguageSettings();
+					SaveSettings();
 					break;
 				case MENUACTION_LANG_FRE:
 					m_PrefsLanguage = LANGUAGE_FRENCH;
 					m_bFrontEnd_ReloadObrTxtGxt = true;
-					CMenuManager::InitialiseChangedLanguageSettings();
-					CMenuManager::SaveSettings();
+					InitialiseChangedLanguageSettings();
+					SaveSettings();
 					break;
 				case MENUACTION_LANG_GER:
 					m_PrefsLanguage = LANGUAGE_GERMAN;
 					m_bFrontEnd_ReloadObrTxtGxt = true;
-					CMenuManager::InitialiseChangedLanguageSettings();
-					CMenuManager::SaveSettings();
+					InitialiseChangedLanguageSettings();
+					SaveSettings();
 					break;
 				case MENUACTION_LANG_ITA:
 					m_PrefsLanguage = LANGUAGE_ITALIAN;
 					m_bFrontEnd_ReloadObrTxtGxt = true;
-					CMenuManager::InitialiseChangedLanguageSettings();
-					CMenuManager::SaveSettings();
+					InitialiseChangedLanguageSettings();
+					SaveSettings();
 					break;
 				case MENUACTION_LANG_SPA:
 					m_PrefsLanguage = LANGUAGE_SPANISH;
 					m_bFrontEnd_ReloadObrTxtGxt = true;
-					CMenuManager::InitialiseChangedLanguageSettings();
+					InitialiseChangedLanguageSettings();
 					SaveSettings();
 					break;
 #ifdef MORE_LANGUAGES
@@ -2968,7 +4263,7 @@ CMenuManager::ProcessButtonPresses(void)
 				case MENUACTION_LANG_JAP:
 					m_PrefsLanguage = LANGUAGE_JAPANESE;
 					m_bFrontEnd_ReloadObrTxtGxt = true;
-					CMenuManager::InitialiseChangedLanguageSettings();
+					InitialiseChangedLanguageSettings();
 					SaveSettings();
 					break;
 #endif
@@ -3000,7 +4295,7 @@ CMenuManager::ProcessButtonPresses(void)
 					if (changeMenu) {
 						if (strncmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEDS_TB", 8) == 0) {
 #ifndef TIDY_UP_PBP
-							CMenuManager::ResetHelperText();
+							ResetHelperText();
 							if (!m_bGameNotLoaded)
 								ChangeScreen(aScreens[m_nCurrScreen].m_PreviousPage[1], aScreens[m_nCurrScreen].m_ParentEntry[1], true, true);
 							else
@@ -3010,6 +4305,12 @@ CMenuManager::ProcessButtonPresses(void)
 							break;
 #endif
 						} else {
+#ifdef MENU_MAP
+							if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu == MENUPAGE_MAP) {
+								bMapLoaded = false;
+							}
+
+#endif
 							ChangeScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu, 0, true, true);
 						}
 					}
@@ -3028,11 +4329,10 @@ CMenuManager::ProcessButtonPresses(void)
 					break;
 				}
 				case MENUACTION_NEWGAME:
-					CMenuManager::DoSettingsBeforeStartingAGame();
+					DoSettingsBeforeStartingAGame();
 					break;
 				case MENUACTION_RELOADIDE:
-					// TODO
-					// CFileLoader::ReloadObjectTypes("GTA3.IDE");
+					CFileLoader::ReloadObjectTypes("GTA3.IDE");
 					break;
 				case MENUACTION_RELOADIPL:
 					CGame::ReloadIPLs();
@@ -3043,7 +4343,7 @@ CMenuManager::ProcessButtonPresses(void)
 				case MENUACTION_MEMCARDSAVECONFIRM:
 					return;
 				case MENUACTION_RESUME_FROM_SAVEZONE:
-					CMenuManager::RequestFrontEndShutDown();
+					RequestFrontEndShutDown();
 					break;
 				case MENUACTION_MPMAP_LIBERTY:
 				case MENUACTION_MPMAP_REDLIGHT:
@@ -3053,8 +4353,8 @@ CMenuManager::ProcessButtonPresses(void)
 				case MENUACTION_MPMAP_INDUSTPARK:
 				case MENUACTION_MPMAP_DOCKS:
 				case MENUACTION_MPMAP_STAUNTON:
-					sthWithButtons = option - MENUACTION_MPMAP_LIBERTY;
-					CMenuManager::SaveSettings();
+					m_SelectedMap = option - MENUACTION_MPMAP_LIBERTY;
+					SaveSettings();
 					ChangeScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu, 0, true, true);
 					break;
 				case MENUACTION_MPMAP_DEATHMATCH1:
@@ -3065,14 +4365,14 @@ CMenuManager::ProcessButtonPresses(void)
 				case MENUACTION_MPMAP_CAPTURE:
 				case MENUACTION_MPMAP_RATRACE:
 				case MENUACTION_MPMAP_DOMINATION:
-					sthWithButtons2 = option - MENUACTION_MPMAP_DEATHMATCH1;
-					CMenuManager::SaveSettings();
+					m_SelectedGameType = option - MENUACTION_MPMAP_DEATHMATCH1;
+					SaveSettings();
 					ChangeScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu, 0, true, true);
 					break;
 				case MENUACTION_REDEFCTRL:
 					ChangeScreen(MENUPAGE_KEYBOARD_CONTROLS, 0, true, true);
 					m_nSelectedListRow = 0;
-					m_nCurrExLayer = 19;
+					m_nCurrExLayer = HOVEROPTION_LIST;
 					break;
 				case MENUACTION_GETKEY:
 					m_CurrCntrlAction = GetStartOptionsCntrlConfigScreens() + m_nCurrOption;
@@ -3087,10 +4387,10 @@ CMenuManager::ProcessButtonPresses(void)
 					break;
 				case MENUACTION_RESUME:
 #ifndef TIDY_UP_PBP
-					if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
-						CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
+					if (m_PrefsVsyncDisp != m_PrefsVsync) {
+						m_PrefsVsync = m_PrefsVsyncDisp;
 					}
-					CMenuManager::RequestFrontEndShutDown();
+					RequestFrontEndShutDown();
 #else
 					goBack = true;
 #endif
@@ -3137,31 +4437,30 @@ CMenuManager::ProcessButtonPresses(void)
 				case MENUACTION_PLAYERSETUP:
 					CPlayerSkin::BeginFrontendSkinEdit();
 					ChangeScreen(MENUPAGE_SKIN_SELECT, 0, true, true);
-					m_nCurrExLayer = 19;
-					m_bSkinsFound = 0;
+					m_nCurrExLayer = HOVEROPTION_LIST;
+					m_bSkinsEnumerated = false;
 					break;
 				case MENUACTION_RESTOREDEF:
 					if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
-						CMenuManager::m_PrefsSfxVolume = 102;
+						m_PrefsSfxVolume = 102;
 						m_PrefsSpeakers = 0;
-						CMenuManager::m_PrefsMusicVolume = 102;
-						// unused
-						// byte_95CDB5 = 0; 
-						CMenuManager::m_PrefsRadioStation = HEAD_RADIO;
+						m_PrefsMusicVolume = 102;
+						m_PrefsStereoMono = 0;
+						m_PrefsRadioStation = HEAD_RADIO;
 						DMAudio.SetMusicMasterVolume(102);
-						DMAudio.SetEffectsMasterVolume(CMenuManager::m_PrefsSfxVolume);
-						DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-						DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+						DMAudio.SetEffectsMasterVolume(m_PrefsSfxVolume);
+						DMAudio.SetRadioInCar(m_PrefsRadioStation);
+						DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 						SaveSettings();
 					} else if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) {
-						CMenuManager::m_PrefsFrameLimiter = true;
-						CMenuManager::m_PrefsBrightness = 256;
-						CMenuManager::m_PrefsVsyncDisp = true;
-						CMenuManager::m_PrefsLOD = 1.2f;
-						CMenuManager::m_PrefsVsync = true;
+						m_PrefsFrameLimiter = true;
+						m_PrefsBrightness = 256;
+						m_PrefsVsyncDisp = true;
+						m_PrefsLOD = 1.2f;
+						m_PrefsVsync = true;
 						CRenderer::ms_lodDistScale = 1.2f;
-						CMenuManager::m_PrefsUseWideScreen = false;
-						CMenuManager::m_PrefsShowSubtitles = true;
+						m_PrefsUseWideScreen = false;
+						m_PrefsShowSubtitles = true;
 						m_nDisplayVideoMode = m_nPrefsVideoMode;
 						CMBlur::BlurOn = true;
 						SaveSettings();
@@ -3175,23 +4474,23 @@ CMenuManager::ProcessButtonPresses(void)
 							PSGLOBAL(joy1)->GetCapabilities(&devCaps);
 							ControlsManager.InitDefaultControlConfigJoyPad(devCaps.dwButtons);
 						}
-						CMenuManager::m_ControlMethod = CONTROL_STANDARD;
+						m_ControlMethod = CONTROL_STANDARD;
 						MousePointerStateHelper.bInvertVertically = false;
 						TheCamera.m_fMouseAccelHorzntl = 0.0025f;
 						CVehicle::m_bDisableMouseSteering = true;
 						TheCamera.m_bHeadBob = false;
 						SaveSettings();
 					}
-					CMenuManager::SetHelperText(2);
+					SetHelperText(2);
 					break;
 				case MENUACTION_CTRLMETHOD:
 #ifndef TIDY_UP_PBP
-					if (CMenuManager::m_ControlMethod == CONTROL_CLASSIC) {
+					if (m_ControlMethod == CONTROL_CLASSIC) {
 						CCamera::m_bUseMouse3rdPerson = true;
-						CMenuManager::m_ControlMethod = CONTROL_STANDARD;
+						m_ControlMethod = CONTROL_STANDARD;
 					} else {
 						CCamera::m_bUseMouse3rdPerson = false;
-						CMenuManager::m_ControlMethod = CONTROL_CLASSIC;
+						m_ControlMethod = CONTROL_CLASSIC;
 					}
 					SaveSettings();
 #else
@@ -3200,7 +4499,7 @@ CMenuManager::ProcessButtonPresses(void)
 					break;
 				case MENUACTION_LOADRADIO:
 					ChangeScreen(MENUPAGE_SOUND_SETTINGS, 0, true, true);
-					DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+					DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 					OutputDebugString("STARTED PLAYING FRONTEND AUDIO TRACK");
 					break;
 			}
@@ -3209,7 +4508,7 @@ CMenuManager::ProcessButtonPresses(void)
 	}
 
 	if (goBack) {
-		CMenuManager::ResetHelperText();
+		ResetHelperText();
 		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0);
 #ifdef PS2_LIKE_MENU
 		if (m_nCurrScreen == MENUPAGE_PAUSE_MENU || bottomBarActive) {
@@ -3217,10 +4516,10 @@ CMenuManager::ProcessButtonPresses(void)
 		if (m_nCurrScreen == MENUPAGE_PAUSE_MENU) {
 #endif
 			if (!m_bGameNotLoaded && !m_bMenuStateChanged) {
-				if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
-					CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
+				if (m_PrefsVsyncDisp != m_PrefsVsync) {
+					m_PrefsVsync = m_PrefsVsyncDisp;
 				}
-				CMenuManager::RequestFrontEndShutDown();
+				RequestFrontEndShutDown();
 			}
 
 			// We're already resuming, we don't need further processing.
@@ -3233,7 +4532,7 @@ CMenuManager::ProcessButtonPresses(void)
 #else
 		else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT) {
 #endif
-			CMenuManager::RequestFrontEndShutDown();
+			RequestFrontEndShutDown();
 		}
 		// It's now in ThingsToDoBeforeLeavingPage()
 #ifndef TIDY_UP_PBP
@@ -3281,13 +4580,13 @@ CMenuManager::ProcessButtonPresses(void)
 	if (CPad::GetPad(0)->GetLeft() || CPad::GetPad(0)->GetPedWalkLeftRight() < 0 || CPad::GetPad(0)->GetDPadLeft()) {
 		static uint32 lastSliderDecrease = 0;
 		if (CTimer::GetTimeInMillisecondsPauseMode() - lastSliderDecrease > 150) {
-			CMenuManager::CheckSliderMovement(-1);
+			CheckSliderMovement(-1);
 			lastSliderDecrease = CTimer::GetTimeInMillisecondsPauseMode();
 		}
 	} else if (CPad::GetPad(0)->GetRight() || CPad::GetPad(0)->GetPedWalkLeftRight() > 0 || CPad::GetPad(0)->GetDPadRight()) {
 		static uint32 lastSliderIncrease = 0;
 		if (CTimer::GetTimeInMillisecondsPauseMode() - lastSliderIncrease > 150) {
-			CMenuManager::CheckSliderMovement(1);
+			CheckSliderMovement(1);
 			lastSliderIncrease = CTimer::GetTimeInMillisecondsPauseMode();
 		}
 	}
@@ -3297,7 +4596,7 @@ CMenuManager::ProcessButtonPresses(void)
 		increase = true;
 	} else if (CPad::GetPad(0)->GetMouseWheelUpJustDown() && m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) {
 		increase = true;
-		CMenuManager::CheckSliderMovement(1);
+		CheckSliderMovement(1);
 		m_bShowMouse = true;
 	}
 
@@ -3305,7 +4604,7 @@ CMenuManager::ProcessButtonPresses(void)
 		if (CPad::GetPad(0)->GetMouseWheelDownJustDown()) {
 			if (m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) {
 				decrease = true;
-				CMenuManager::CheckSliderMovement(-1);
+				CheckSliderMovement(-1);
 				m_bShowMouse = true;
 			}
 		}
@@ -3322,22 +4621,22 @@ CMenuManager::ProcessButtonPresses(void)
 	if (changeValueBy != 0) {
 		switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) {
 			case MENUACTION_RADIO:
-				CMenuManager::m_PrefsRadioStation += changeValueBy;
+				m_PrefsRadioStation += changeValueBy;
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
 				if (DMAudio.IsMP3RadioChannelAvailable()) {
-					if (CMenuManager::m_PrefsRadioStation < HEAD_RADIO)
-						CMenuManager::m_PrefsRadioStation = USERTRACK;
-					if (CMenuManager::m_PrefsRadioStation > USERTRACK)
-						CMenuManager::m_PrefsRadioStation = HEAD_RADIO;
+					if (m_PrefsRadioStation < HEAD_RADIO)
+						m_PrefsRadioStation = USERTRACK;
+					if (m_PrefsRadioStation > USERTRACK)
+						m_PrefsRadioStation = HEAD_RADIO;
 				} else {
-					if (CMenuManager::m_PrefsRadioStation < HEAD_RADIO)
-						CMenuManager::m_PrefsRadioStation = CHATTERBOX;
-					if (CMenuManager::m_PrefsRadioStation > CHATTERBOX)
-						CMenuManager::m_PrefsRadioStation = HEAD_RADIO;
+					if (m_PrefsRadioStation < HEAD_RADIO)
+						m_PrefsRadioStation = CHATTERBOX;
+					if (m_PrefsRadioStation > CHATTERBOX)
+						m_PrefsRadioStation = HEAD_RADIO;
 				}
-				CMenuManager::SaveSettings();
-				DMAudio.SetRadioInCar(CMenuManager::m_PrefsRadioStation);
-				DMAudio.PlayFrontEndTrack(CMenuManager::m_PrefsRadioStation, 1);
+				SaveSettings();
+				DMAudio.SetRadioInCar(m_PrefsRadioStation);
+				DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1);
 				OutputDebugString("FRONTEND RADIO STATION CHANGED");
 				break;
 			case MENUACTION_SCREENRES:
@@ -3373,34 +4672,31 @@ CMenuManager::ProcessButtonPresses(void)
 					m_PrefsSpeakers -= changeValueBy;
 					m_PrefsSpeakers = clamp(m_PrefsSpeakers, 0, 2);
 					DMAudio.SetSpeakerConfig(m_PrefsSpeakers);
-					CMenuManager::SaveSettings();
+					SaveSettings();
 					DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
 				}
 				break;
 			case MENUACTION_CTRLMETHOD:
-				CMenuManager::m_ControlMethod = !m_ControlMethod;
+				m_ControlMethod = !m_ControlMethod;
 				CCamera::m_bUseMouse3rdPerson = !m_ControlMethod;
 				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
-				CMenuManager::SaveSettings();
+				SaveSettings();
 				break;
 		}
 		ProcessOnOffMenuOptions();
 		if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) {
 			if (changeValueBy < 1) {
-				field_530 = 0;
+				m_nSelectedContSetupColumn = CONTSETUP_PED_COLUMN;
 			} else {
-				field_530 = 14;
+				m_nSelectedContSetupColumn = CONTSETUP_VEHICLE_COLUMN;
 			}
 			DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
 		}
 	}
 }
-#endif
 
-#if 0
-WRAPPER void CMenuManager::ProcessOnOffMenuOptions() { EAXJMP(0x48AE60); }
-#else
-void CMenuManager::ProcessOnOffMenuOptions()
+void
+CMenuManager::ProcessOnOffMenuOptions()
 {
 	switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) {
 	case MENUACTION_CTRLVIBRATION:
@@ -3478,7 +4774,9 @@ void CMenuManager::ProcessOnOffMenuOptions()
 		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
 		break;
 	case MENUACTION_MP_PLAYERCOLOR:
-		assert(0 && "Not implemented");
+		PickNewPlayerColour();
+		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
+		SaveSettings();
 		break;
 	case MENUACTION_SHOWHEADBOB:
 		TheCamera.m_bHeadBob = !TheCamera.m_bHeadBob;
@@ -3503,34 +4801,29 @@ void CMenuManager::ProcessOnOffMenuOptions()
 		break;
 	}
 }
-#endif
 
-void CMenuManager::RequestFrontEndShutDown()
+void
+CMenuManager::RequestFrontEndShutDown()
 {
 	m_bShutDownFrontEndRequested = true;
 	DMAudio.ChangeMusicMode(MUSICMODE_GAME);
 }
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::RequestFrontEndStartUp() { EAXJMP(0x488770); }
-#else
-void CMenuManager::RequestFrontEndStartUp()
+void
+CMenuManager::RequestFrontEndStartUp()
 {
 	m_bStartUpFrontEndRequested = true;
 }
-#endif
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::ResetHelperText() { EAXJMP(0x48B470); }
-#else
-void CMenuManager::ResetHelperText() 
+void
+CMenuManager::ResetHelperText() 
 {
 	m_nHelperTextMsgId = 0;
 	m_nHelperTextAlpha = 300;
 }
-#endif
 
-void CMenuManager::SaveLoadFileError_SetUpErrorScreen()
+void
+CMenuManager::SaveLoadFileError_SetUpErrorScreen()
 {
 	switch (PcSaveHelper.nErrorCode) {
 		case SAVESTATUS_ERR_SAVE_CREATE:
@@ -3554,27 +4847,22 @@ void CMenuManager::SaveLoadFileError_SetUpErrorScreen()
 	}
 }
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::SetHelperText(int text) { EAXJMP(0x48B450); }
-#else
-void CMenuManager::SetHelperText(int text)
+void
+CMenuManager::SetHelperText(int text)
 {
 	m_nHelperTextMsgId = text;
 	m_nHelperTextAlpha = 300;
 }
-#endif
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); }
-#else
-void CMenuManager::ShutdownJustMenu()
+void
+CMenuManager::ShutdownJustMenu()
 {
 	m_bMenuActive = false;
 	CTimer::EndUserPause();
 }
-#endif
 
-float CMenuManager::StretchX(float x)
+float
+CMenuManager::StretchX(float x)
 {
 	if (SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH)
 		return x;
@@ -3592,12 +4880,10 @@ float CMenuManager::StretchY(float y)
 		return SCREEN_STRETCH_Y(y);
 }
 
-#if 0
-WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); }
-#else
-void CMenuManager::SwitchMenuOnAndOff()
+void
+CMenuManager::SwitchMenuOnAndOff()
 {
-	bool menuWasActive = !!m_bMenuActive;
+	bool menuWasActive = GetIsMenuActive();
 
 	// Reminder: You need REGISTER_START_BUTTON defined to make it work.
 	if (CPad::GetPad(0)->GetStartJustDown() 
@@ -3627,9 +4913,20 @@ void CMenuManager::SwitchMenuOnAndOff()
 			m_bStartUpFrontEndRequested = false;
 			pControlEdit = nil;
 			m_bShutDownFrontEndRequested = false;
-			DisplayComboButtonErrMsg = 0;
-			CPad::GetPad(0)->Clear(0);
-			CPad::GetPad(1)->Clear(0);
+			DisplayComboButtonErrMsg = false;
+
+#ifdef REGISTER_START_BUTTON
+			int16 start1 = CPad::GetPad(0)->PCTempJoyState.Start, start2 = CPad::GetPad(0)->PCTempKeyState.Start,
+				start3 = CPad::GetPad(0)->OldState.Start, start4 = CPad::GetPad(0)->NewState.Start;
+#endif
+			CPad::GetPad(0)->Clear(false);
+			CPad::GetPad(1)->Clear(false);
+#ifdef REGISTER_START_BUTTON
+			CPad::GetPad(0)->PCTempJoyState.Start = start1;
+			CPad::GetPad(0)->PCTempKeyState.Start = start2;
+			CPad::GetPad(0)->OldState.Start = start3;
+			CPad::GetPad(0)->NewState.Start = start4;
+#endif
 			m_nCurrScreen = MENUPAGE_NONE;
 		}
 	}
@@ -3662,12 +4959,9 @@ void CMenuManager::SwitchMenuOnAndOff()
 	m_bStartUpFrontEndRequested = false;
 	m_bShutDownFrontEndRequested = false;
 }
-#endif
 
-#if 0
-WRAPPER void CMenuManager::UnloadTextures() { EAXJMP(0x47A440); }
-#else
-void CMenuManager::UnloadTextures()
+void
+CMenuManager::UnloadTextures()
 {
 	if (!m_bSpritesLoaded)
 		return;
@@ -3682,33 +4976,645 @@ void CMenuManager::UnloadTextures()
 	printf("REMOVE menu textures\n");
 	for (int i = 0; i < ARRAY_SIZE(MenuFilenames); ++i)
 		m_aMenuSprites[i].Delete();
-
+#ifdef MENU_MAP
+	for (int i = 0; i < ARRAY_SIZE(MapFilenames); ++i)
+		m_aMapSprites[i].Delete();
+#endif
 	int menu = CTxdStore::FindTxdSlot("menu");
 	CTxdStore::RemoveTxd(menu);
 
 	m_bSpritesLoaded = false;
 }
+
+void
+CMenuManager::WaitForUserCD()
+{
+	CSprite2d *splash;
+	char *splashscreen = nil;
+
+#ifndef RANDOMSPLASH
+	if (CGame::frenchGame || CGame::germanGame || !CGame::nastyGame)
+		splashscreen = "mainsc2";
+	else
+		splashscreen = "mainsc1";
 #endif
 
-#if DONT_USE_SUSPICIOUS_FUNCS
-WRAPPER void CMenuManager::WaitForUserCD(void) { EAXJMP(0x48ADD0); }
-#else
-void CMenuManager::WaitForUserCD()
-{
-	LoadSplash(0);
-	if (!RsGlobal.quit) {
-		HandleExit();
-		CPad::UpdatePads();
-		MessageScreen("NO_PCCD");
+	splash = LoadSplash(splashscreen);
 
-		if (GetPadBack()) {
-			m_bQuitGameNoCD = true;
-			RsEventHandler(rsQUITAPP, 0);
-		}
+	if (RsGlobal.quit)
+		return;
+
+	HandleExit();
+	CPad::UpdatePads();
+	MessageScreen("NO_PCCD");
+
+	if (CPad::GetPad(0)->GetEscapeJustDown()) {
+		m_bQuitGameNoCD = true;
+		RsEventHandler(rsQUITAPP, nil);
 	}
 }
+
+void
+CMenuManager::PrintController(void)
+{
+	// FIX: Originally this function doesn't have StretchX/Y, everything had constant pixel size (due to screen was abandoned early?)
+	//		Also texts and their alignment were very bad, so I tried to make them readable (commented out the original code, and marked the ones I added with X)
+
+	m_aFrontEndSprites[FE_CONTROLLERSH].Draw(MENU_X_LEFT_ALIGNED(160.0f), MENU_Y(160.0f), MENU_X(240.0f), MENU_Y(180.0f), CRGBA(0, 0, 0, 255));
+	m_aFrontEndSprites[FE_CONTROLLER].Draw(MENU_X_LEFT_ALIGNED(160.0f), MENU_Y(160.0f), MENU_X(235.2f), MENU_Y(175.2f), CRGBA(255, 255, 255, 255));
+	if (m_DisplayControllerOnFoot) {
+		if (CTimer::GetTimeInMillisecondsPauseMode() & 0x400)
+			m_aFrontEndSprites[FE_ARROWS1].Draw(MENU_X_LEFT_ALIGNED(160.0f), MENU_Y(160.0f), MENU_X(235.2f), MENU_Y(175.2f), CRGBA(255, 255, 255, 255));
+		else
+			m_aFrontEndSprites[FE_ARROWS3].Draw(MENU_X_LEFT_ALIGNED(160.0f), MENU_Y(160.0f), MENU_X(235.2f), MENU_Y(175.2f), CRGBA(255, 255, 255, 255));
+	} else {
+		if (CTimer::GetTimeInMillisecondsPauseMode() & 0x400)
+			m_aFrontEndSprites[FE_ARROWS2].Draw(MENU_X_LEFT_ALIGNED(160.0f), MENU_Y(160.0f), MENU_X(235.2f), MENU_Y(175.2f), CRGBA(255, 255, 255, 255));
+		else
+			m_aFrontEndSprites[FE_ARROWS4].Draw(MENU_X_LEFT_ALIGNED(160.0f), MENU_Y(160.0f), MENU_X(235.2f), MENU_Y(175.2f), CRGBA(255, 255, 255, 255));
+	}
+
+	CFont::SetFontStyle(FONT_BANK);  // X
+
+	// CFont::SetScale(0.4f, 0.4f);
+	CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE), MENU_Y(SMALLESTTEXT_Y_SCALE)); // X
+
+	// CFont::SetColor(CRGBA(128, 128, 128, FadeIn(255)));
+	CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(255))); // X
+	CFont::SetDropShadowPosition(1); // X
+	CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255))); // X
+
+	if (m_DisplayControllerOnFoot) {
+		switch (CPad::GetPad(0)->Mode) {
+			case 0:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_CWL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_LOF"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_MOV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_MOV"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_CWR"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_TAR"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_JUM"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_ENV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_ATT"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_RUN"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_FPC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_LB3"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_R3"));
+				break;
+			case 1:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_CWL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_LOF"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_MOV"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_NA"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_CWR"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_TAR"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_JUM"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_ENV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_ATT"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_RUN"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_FPC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_LB3"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_R3"));
+				break;
+			case 2:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_CWL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_ENV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_MOV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_MOV"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_CWR"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_TAR"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_JUM"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_LOF"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_RUN"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_ATT"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_FPC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_LB3"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_R3"));
+				break;
+			case 3:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_CWL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_TAR"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_NA"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_MOV"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_CWR"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_TAR"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_JUM"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_LOF"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_RUN"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_ATT"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_FPC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_LB3"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_R3"));
+				break;
+			default:
+				return;
+		}
+	} else {
+		switch (CPad::GetPad(0)->Mode) {
+			case 0:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_LL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_RSC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_VES"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_VES"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_HO3"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_LB"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_LR"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_HAB"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_BRA"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_EXV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_CAW"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_ACC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_TUC"));
+				// FIX: Coordinates of this line is undefined in PC...
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(304.0f), TheText.Get("FEC_SM3"));
+				break;
+			case 1:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_LL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_HOR"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_VES"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_NA"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_RSC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_LB"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_LR"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_HAB"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_BRA"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_EXV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_CAW"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_ACC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_TUC"));
+				// FIX: Coordinates of this line is undefined in PC...
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(304.0f), TheText.Get("FEC_SM3"));
+				break;
+			case 2:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_LL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_EXV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_VES"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_VES"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_RS3"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_LB"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_LR"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_HOR"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_BRA"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_HAB"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_CAW"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_ACC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_TUC"));
+				// FIX: Coordinates of this line is undefined in PC...
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(304.0f), TheText.Get("FEC_SM3"));
+				break;
+			case 3:
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(210.0f), MENU_Y(146.0f), TheText.Get("FEC_LL"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(185.0f), TheText.Get("FEC_HAB"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(225.0f), TheText.Get("FEC_TUC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(156.0f), MENU_Y(257.0f), TheText.Get("FEC_VES"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(263.0f), MENU_Y(301.0f), TheText.Get("FEC_HO3"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(290.0f), MENU_Y(288.0f), TheText.Get("FEC_CAM"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(344.0f), MENU_Y(146.0f), TheText.Get("FEC_PAU"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(185.0f), TheText.Get("FEC_LB"));
+				CFont::SetRightJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(304.0f), MENU_Y(178.0f), TheText.Get("FEC_LR"));
+				CFont::SetJustifyOn(); // X
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(212.0f), TheText.Get("FEC_CAW"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(225.0f), TheText.Get("FEC_SMT"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(238.0f), TheText.Get("FEC_EXV"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(254.0f), TheText.Get("FEC_RSC"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(269.0f), TheText.Get("FEC_NA"));
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(282.0f), TheText.Get("FEC_ACC"));
+				// FIX: Coordinates of this line is undefined in PC...
+				CFont::PrintString(MENU_X_LEFT_ALIGNED(398.0f), MENU_Y(304.0f), TheText.Get("FEC_BRA"));
+				break;
+			default:
+				return;
+		}
+	}
+
+	CFont::SetDropShadowPosition(0); // X
+}
+
+#ifdef MENU_MAP
+
+#define ZOOM(x, y, in) \
+	do { \
+		if(fMapSize > SCREEN_WIDTH * 2 && in) \
+			break; \
+		float z2 = in? 1.1f : 1.f/1.1f; \
+		fMapCenterX += (x - fMapCenterX) * (1.0f - z2); \
+		fMapCenterY += (y - fMapCenterY) * (1.0f - z2); \
+		\
+		if (fMapSize < SCREEN_WIDTH / 3 && !in) \
+			break; \
+		\
+		fMapSize *= z2; \
+	} while(0) \
+
+void
+CMenuManager::PrintMap(void)
+{
+	bMenuMapActive = true;
+	CRadar::InitFrontEndMap();
+
+	if (!bMapLoaded) {
+		fMapCenterX = SCREEN_WIDTH / 2;
+		fMapCenterY = SCREEN_HEIGHT / 3;
+		fMapSize = SCREEN_HEIGHT / CDraw::GetAspectRatio();
+		bMapMouseShownOnce = false;
+		bMapLoaded = true;
+
+		// Let's wait for a frame to not toggle the waypoint
+		if (CPad::GetPad(0)->NewState.Cross) {
+			bMenuMapActive = false;
+			return;
+		}
+	}
+
+	// Because fMapSize is half of the map length, and map consists of 3x3 tiles.
+	float halfTile = fMapSize / 3.0f;
+
+	// Darken background a bit
+	CSprite2d::DrawRect(CRect(0, 0,
+		SCREEN_WIDTH, SCREEN_HEIGHT),
+		CRGBA(0, 0, 0, FadeIn(128)));
+
+	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+
+	if (SCREEN_WIDTH >= fMapCenterX - fMapSize || SCREEN_HEIGHT >= fMapCenterY - fMapSize) {
+		m_aMapSprites[MAPTOP1].Draw(CRect(fMapCenterX - fMapSize, fMapCenterY - fMapSize,
+			fMapCenterX - halfTile, fMapCenterY - halfTile), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX - halfTile || SCREEN_HEIGHT >= fMapCenterY - fMapSize) {
+		m_aMapSprites[MAPTOP2].Draw(CRect(fMapCenterX - halfTile, fMapCenterY - fMapSize,
+			fMapCenterX + halfTile, fMapCenterY - halfTile), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX + halfTile || SCREEN_HEIGHT >= fMapCenterY - fMapSize) {
+		m_aMapSprites[MAPTOP3].Draw(CRect(fMapCenterX + halfTile, fMapCenterY - fMapSize,
+			fMapCenterX + fMapSize, fMapCenterY - halfTile), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX - fMapSize || SCREEN_HEIGHT >= fMapCenterY - halfTile) {
+		m_aMapSprites[MAPMID1].Draw(CRect(fMapCenterX - fMapSize, fMapCenterY - halfTile,
+			fMapCenterX - halfTile, fMapCenterY + halfTile), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX - halfTile || SCREEN_HEIGHT >= fMapCenterY - halfTile) {
+		m_aMapSprites[MAPMID2].Draw(CRect(fMapCenterX - halfTile, fMapCenterY - halfTile,
+			fMapCenterX + halfTile, fMapCenterY + halfTile), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX + halfTile || SCREEN_HEIGHT >= fMapCenterY - halfTile) {
+		m_aMapSprites[MAPMID3].Draw(CRect(fMapCenterX + halfTile, fMapCenterY - halfTile,
+			fMapCenterX + fMapSize, fMapCenterY + halfTile), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX - fMapSize || SCREEN_HEIGHT >= fMapCenterY + halfTile) {
+		m_aMapSprites[MAPBOT1].Draw(CRect(fMapCenterX - fMapSize, fMapCenterY + halfTile,
+			fMapCenterX - halfTile, fMapCenterY + fMapSize), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX - halfTile || SCREEN_HEIGHT >= fMapCenterY + halfTile) {
+		m_aMapSprites[MAPBOT2].Draw(CRect(fMapCenterX - halfTile, fMapCenterY + halfTile,
+			fMapCenterX + halfTile, fMapCenterY + fMapSize), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	if (SCREEN_WIDTH >= fMapCenterX + halfTile || SCREEN_HEIGHT >= fMapCenterY + halfTile) {
+		m_aMapSprites[MAPBOT3].Draw(CRect(fMapCenterX + halfTile, fMapCenterY + halfTile,
+			fMapCenterX + fMapSize, fMapCenterY + fMapSize), CRGBA(255, 255, 255, FadeIn(255)));
+	}
+
+	CRadar::DrawBlips();
+
+	CVector2D mapPoint;
+	mapPoint.x = m_nMousePosX;
+	mapPoint.y = m_nMousePosY;
+
+	if (m_bShowMouse) {
+		bMapMouseShownOnce = true;
+	} else if (!bMapMouseShownOnce) {
+		mapPoint.x = SCREEN_WIDTH / 2;
+		mapPoint.y = SCREEN_HEIGHT / 2;
+	}
+
+	CSprite2d::DrawRect(CRect(mapPoint.x - MENU_X(1.0f), 0.0f,
+		mapPoint.x + MENU_X(1.0f), SCREEN_HEIGHT),
+		CRGBA(0, 0, 0, 150));
+	CSprite2d::DrawRect(CRect(0.0f, mapPoint.y + MENU_X(1.0f),
+		SCREEN_WIDTH, mapPoint.y - MENU_X(1.0f)),
+		CRGBA(0, 0, 0, 150));
+
+	if (CPad::GetPad(0)->GetRightMouseJustDown() || CPad::GetPad(0)->GetCrossJustDown()) {
+		if (mapPoint.y > fMapCenterY - fMapSize && mapPoint.y < fMapCenterY + fMapSize &&
+			mapPoint.x > fMapCenterX - fMapSize && mapPoint.x < fMapCenterX + fMapSize) {
+
+			float diffX = fMapCenterX - fMapSize, diffY = fMapCenterY - fMapSize;
+			float x = ((mapPoint.x - diffX) / (fMapSize * 2)) * 4000.0f - 2000.0f;
+			float y = 2000.0f - ((mapPoint.y - diffY) / (fMapSize * 2)) * 4000.0f;
+			CRadar::ToggleTargetMarker(x, y);
+			DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0);
+		}
+	}
+
+	if (CPad::GetPad(0)->GetLeftMouse()) {
+		fMapCenterX += m_nMousePosX - m_nMouseOldPosX;
+		fMapCenterY += m_nMousePosY - m_nMouseOldPosY;
+	} else if (CPad::GetPad(0)->GetLeft() || CPad::GetPad(0)->GetDPadLeft()) {
+		fMapCenterX += 15.0f;
+	} else if (CPad::GetPad(0)->GetRight() || CPad::GetPad(0)->GetDPadRight()) {
+		fMapCenterX -= 15.0f;
+	} else if (CPad::GetPad(0)->GetLeftStickX()) {
+		fMapCenterX -= CPad::GetPad(0)->GetLeftStickX() / 128.0f * 20.0f;
+	}
+
+	if (CPad::GetPad(0)->GetUp() || CPad::GetPad(0)->GetDPadUp()) {
+		fMapCenterY += 15.0f;
+	} else if (CPad::GetPad(0)->GetDown() || CPad::GetPad(0)->GetDPadDown()) {
+		fMapCenterY -= 15.0f;
+	} else if (CPad::GetPad(0)->GetLeftStickY()) {
+		fMapCenterY -= CPad::GetPad(0)->GetLeftStickY() / 128.0f * 20.0f;
+	}
+
+	if (CPad::GetPad(0)->GetMouseWheelDown() || CPad::GetPad(0)->GetPageDown() || CPad::GetPad(0)->GetRightShoulder2()) {
+		if (CPad::GetPad(0)->GetMouseWheelDown())
+			ZOOM(mapPoint.x, mapPoint.y, false);
+		else
+			ZOOM(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, false);
+	} else if (CPad::GetPad(0)->GetMouseWheelUp() || CPad::GetPad(0)->GetPageUp() || CPad::GetPad(0)->GetRightShoulder1()) {
+		if (CPad::GetPad(0)->GetMouseWheelUp())
+			ZOOM(mapPoint.x, mapPoint.y, true);
+		else
+			ZOOM(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, true);
+	}
+	
+	if (fMapCenterX - fMapSize > SCREEN_WIDTH / 2)
+		fMapCenterX = fMapSize + SCREEN_WIDTH / 2;
+
+	if (fMapCenterX + fMapSize < SCREEN_WIDTH / 2)
+		fMapCenterX = SCREEN_WIDTH / 2 - fMapSize;
+
+	if (fMapCenterY + fMapSize < SCREEN_HEIGHT - MENU_Y(60.0f))
+		fMapCenterY = SCREEN_HEIGHT - MENU_Y(60.0f) - fMapSize;
+	
+	fMapCenterY = min(fMapCenterY, fMapSize); // To not show beyond north border
+
+	bMenuMapActive = false;
+
+	// CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(5.0f)); // From VC
+	// CFont::SetRightJustifyWrap(10.0f);
+
+	CSprite2d::DrawRect(CRect(MENU_X(14.0f), SCREEN_STRETCH_FROM_BOTTOM(95.0f),
+		SCREEN_STRETCH_FROM_RIGHT(11.0f), SCREEN_STRETCH_FROM_BOTTOM(59.0f)),
+		CRGBA(235, 170, 50, 255));
+
+	CFont::SetScale(MENU_X(0.4f), MENU_Y(0.7f));
+	CFont::SetFontStyle(FONT_BANK);
+	CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
+
+	float nextX = MENU_X(30.0f), nextY = 95.0f;
+	wchar *text;
+#define TEXT_PIECE(key,extraSpace) \
+	text = TheText.Get(key); CFont::PrintString(nextX, SCREEN_SCALE_FROM_BOTTOM(nextY), text); nextX += CFont::GetStringWidth(text, true) + MENU_X(extraSpace);
+
+	TEXT_PIECE("FEC_MWF", 3.0f);
+	TEXT_PIECE("FEC_PGU", 1.0f);
+	TEXT_PIECE("FEC_IBT", 1.0f);
+	TEXT_PIECE("FEC_ZIN", 20.0f);
+	TEXT_PIECE("FEC_MWB", 3.0f);
+	TEXT_PIECE("FEC_PGD", 1.0f);
+	TEXT_PIECE("FEC_IBT", 1.0f);
+	CFont::PrintString(nextX, SCREEN_SCALE_FROM_BOTTOM(nextY), TheText.Get("FEC_ZOT")); nextX = MENU_X(30.0f); nextY -= 11.0f;
+	TEXT_PIECE("FEC_UPA", 2.0f);
+	TEXT_PIECE("FEC_DWA", 2.0f);
+	TEXT_PIECE("FEC_LFA", 2.0f);
+	TEXT_PIECE("FEC_RFA", 2.0f);
+	TEXT_PIECE("FEC_MSL", 1.0f);
+	TEXT_PIECE("FEC_IBT", 1.0f);
+	CFont::PrintString(nextX, SCREEN_SCALE_FROM_BOTTOM(nextY), TheText.Get("FEC_MOV")); nextX = MENU_X(30.0f); nextY -= 11.0f;
+	TEXT_PIECE("FEC_MSR", 2.0f);
+	TEXT_PIECE("FEC_IBT", 1.0f);
+	CFont::PrintString(nextX, SCREEN_SCALE_FROM_BOTTOM(nextY), TheText.Get("FEC_TAR"));
+#undef TEXT_PIECE
+}
+
+#undef ZOOM
 #endif
 
+// rowIdx 99999 returns total numbers of rows. otherwise it returns 0.
+int
+CMenuManager::ConstructStatLine(int rowIdx)
+{
+#define STAT_LINE(str, left, isFloat, right) \
+	do { \
+		if(counter == rowIdx){ \
+			BuildStatLine(str, left, isFloat, right); \
+			return 0; \
+		} counter++; \
+	} while(0)
+
+	int counter = 0, nTemp;
+
+	STAT_LINE("PL_STAT", nil, false, nil);
+
+	int percentCompleted = (CStats::TotalProgressInGame == 0 ? 0 :
+		CStats::ProgressMade * 100.0f / (CGame::nastyGame ? CStats::TotalProgressInGame : CStats::TotalProgressInGame - 1));
+	percentCompleted = min(percentCompleted, 100);
+
+	STAT_LINE("PER_COM", &percentCompleted, false, nil);
+	STAT_LINE("NMISON", &CStats::MissionsGiven, false, nil);
+	STAT_LINE("FEST_MP", &CStats::MissionsPassed, 0, &CStats::TotalNumberMissions);
+	if (CGame::nastyGame) {
+		STAT_LINE("FEST_RP", &CStats::NumberKillFrenziesPassed, 0, &CStats::TotalNumberKillFrenzies);
+	}
+	
+	CPlayerInfo &player = CWorld::Players[CWorld::PlayerInFocus];
+	float packagesPercent = 0.0f;
+	if (player.m_nTotalPackages != 0)
+		packagesPercent = player.m_nCollectedPackages * 100.0f / player.m_nTotalPackages;
+
+	STAT_LINE("PERPIC", &packagesPercent, 0, &(nTemp = 100));
+	STAT_LINE("NOUNIF", &CStats::TotalNumberOfUniqueJumps, 0, &CStats::NumberOfUniqueJumpsFound);
+	STAT_LINE("DAYSPS", &CStats::DaysPassed, false, nil);
+	if (CGame::nastyGame) {
+		STAT_LINE("PE_WAST", &CStats::PeopleKilledByPlayer, false, nil);
+		STAT_LINE("PE_WSOT", &CStats::PeopleKilledByOthers, false, nil);
+	}
+	STAT_LINE("CAR_EXP", &CStats::CarsExploded, false, nil);
+	STAT_LINE("TM_BUST", &CStats::TimesArrested, false, nil);
+	STAT_LINE("TM_DED", &CStats::TimesDied, false, nil);
+	STAT_LINE("GNG_WST", &(nTemp = CStats::PedsKilledOfThisType[PEDTYPE_GANG9] + CStats::PedsKilledOfThisType[PEDTYPE_GANG8]
+			+ CStats::PedsKilledOfThisType[PEDTYPE_GANG7] + CStats::PedsKilledOfThisType[PEDTYPE_GANG6]
+			+ CStats::PedsKilledOfThisType[PEDTYPE_GANG5] + CStats::PedsKilledOfThisType[PEDTYPE_GANG4]
+			+ CStats::PedsKilledOfThisType[PEDTYPE_GANG3] + CStats::PedsKilledOfThisType[PEDTYPE_GANG2]
+			+ CStats::PedsKilledOfThisType[PEDTYPE_GANG1]), false, nil);
+	STAT_LINE("DED_CRI", &(nTemp = CStats::PedsKilledOfThisType[PEDTYPE_CRIMINAL]), false, nil);
+	STAT_LINE("HEL_DST", &CStats::HelisDestroyed, false, nil);
+	STAT_LINE("KGS_EXP", &CStats::KgsOfExplosivesUsed, false, nil);
+	STAT_LINE("ACCURA", &(nTemp = (CStats::InstantHitsFiredByPlayer == 0 ? 0 :
+			CStats::InstantHitsHitByPlayer * 100.0f / CStats::InstantHitsFiredByPlayer)), false, nil);
+	
+	if (CStats::ElBurroTime > 0) {
+		STAT_LINE("ELBURRO", &CStats::ElBurroTime, false, nil);
+	}
+	if (CStats::Record4x4One > 0) {
+		STAT_LINE("FEST_R1", &CStats::Record4x4One, false, nil);
+	}
+	if (CStats::Record4x4Two > 0) {
+		STAT_LINE("FEST_R2", &CStats::Record4x4Two, false, nil);
+	}
+	if (CStats::Record4x4Three > 0) {
+		STAT_LINE("FEST_R3", &CStats::Record4x4Three, false, nil);
+	}
+	if (CStats::Record4x4Mayhem > 0) {
+		STAT_LINE("FEST_RM", &CStats::Record4x4Mayhem, false, nil);
+	}
+	if (CStats::LongestFlightInDodo > 0) {
+		STAT_LINE("FEST_LF", &CStats::LongestFlightInDodo, false, nil);
+	}
+	if (CStats::TimeTakenDefuseMission > 0) {
+		STAT_LINE("FEST_BD", &CStats::TimeTakenDefuseMission, false, nil);
+	}
+	STAT_LINE("CAR_CRU", &CStats::CarsCrushed, false, nil);
+
+	if (CStats::HighestScores[0] > 0) {
+		STAT_LINE("FEST_BB", nil, false, nil);
+		STAT_LINE("FEST_H0", &CStats::HighestScores[0], false, nil);
+	}
+	if (CStats::HighestScores[4] + CStats::HighestScores[3] + CStats::HighestScores[2] + CStats::HighestScores[1] > 0) {
+		STAT_LINE("FEST_GC", nil, false, nil);
+	}
+	if (CStats::HighestScores[1] > 0) {
+		STAT_LINE("FEST_H1", &CStats::HighestScores[1], false, nil);
+	}
+	if (CStats::HighestScores[2] > 0) {
+		STAT_LINE("FEST_H2", &CStats::HighestScores[2], false, nil);
+	}
+	if (CStats::HighestScores[3] > 0) {
+		STAT_LINE("FEST_H3", &CStats::HighestScores[3], false, nil);
+	}
+	if (CStats::HighestScores[4] > 0) {
+		STAT_LINE("FEST_H4", &CStats::HighestScores[4], false, nil);
+	}
+
+	switch (m_PrefsLanguage) {
+		case LANGUAGE_AMERICAN:
+#ifndef USE_MEASUREMENTS_IN_METERS
+			float fTemp;
+			STAT_LINE("FEST_DF", &(fTemp = CStats::DistanceTravelledOnFoot * MILES_IN_METER), true, nil);
+			STAT_LINE("FEST_DC", &(fTemp = CStats::DistanceTravelledInVehicle * MILES_IN_METER), true, nil);
+			STAT_LINE("MMRAIN", &CStats::mmRain, false, nil);
+			STAT_LINE("MXCARD", &(fTemp = CStats::MaximumJumpDistance * FEET_IN_METER), true, nil);
+			STAT_LINE("MXCARJ", &(fTemp = CStats::MaximumJumpHeight * FEET_IN_METER), true, nil);
+			break;
+#endif
+		case LANGUAGE_FRENCH:
+		case LANGUAGE_GERMAN:
+		case LANGUAGE_ITALIAN:
+		case LANGUAGE_SPANISH:
+#ifdef MORE_LANGUAGES
+		case LANGUAGE_RUSSIAN:
+#endif
+			STAT_LINE("FESTDFM", &CStats::DistanceTravelledOnFoot, true, nil);
+			STAT_LINE("FESTDCM", &CStats::DistanceTravelledInVehicle, true, nil);
+			STAT_LINE("MMRAIN", &CStats::mmRain, false, nil);
+			STAT_LINE("MXCARDM", &CStats::MaximumJumpDistance, true, nil);
+			STAT_LINE("MXCARJM", &CStats::MaximumJumpHeight, true, nil);
+			break;
+		default:
+			break;
+	}
+
+	STAT_LINE("MXFLIP", &CStats::MaximumJumpFlips, false, nil);
+	STAT_LINE("MXJUMP", &CStats::MaximumJumpSpins, false, nil);
+	STAT_LINE("BSTSTU", nil, false, nil);
+
+	if (counter == rowIdx) {
+		gUString[0] = '\0';
+		switch (CStats::BestStuntJump) {
+			case 1:
+				UnicodeStrcpy(gUString2, TheText.Get("INSTUN"));
+				return 0;
+			case 2:
+				UnicodeStrcpy(gUString2, TheText.Get("PRINST"));
+				return 0;
+			case 3:
+				UnicodeStrcpy(gUString2, TheText.Get("DBINST"));
+				return 0;
+			case 4:
+				UnicodeStrcpy(gUString2, TheText.Get("DBPINS"));
+				return 0;
+			case 5:
+				UnicodeStrcpy(gUString2, TheText.Get("TRINST"));
+				return 0;
+			case 6:
+				UnicodeStrcpy(gUString2, TheText.Get("PRTRST"));
+				return 0;
+			case 7:
+				UnicodeStrcpy(gUString2, TheText.Get("QUINST"));
+				return 0;
+			case 8:
+				UnicodeStrcpy(gUString2, TheText.Get("PQUINS"));
+				return 0;
+			default:
+				UnicodeStrcpy(gUString2, TheText.Get("NOSTUC"));
+				return 0;
+		}
+	}
+	counter++;
+	STAT_LINE("PASDRO", &CStats::PassengersDroppedOffWithTaxi, false, nil);
+	STAT_LINE("MONTAX", &CStats::MoneyMadeWithTaxi, false, nil);
+	STAT_LINE("FEST_LS", &CStats::LivesSavedWithAmbulance, false, nil);
+	STAT_LINE("FEST_HA", &CStats::HighestLevelAmbulanceMission, false, nil);
+	STAT_LINE("FEST_CC", &CStats::CriminalsCaught, false, nil);
+	STAT_LINE("FEST_FE", &CStats::FiresExtinguished, false, nil);
+	STAT_LINE("DAYPLC", &(nTemp = CTimer::GetTimeInMilliseconds() + 100), false, nil);
+	return counter;
+
+#undef STAT_LINE
+}
+
 #if 0
 uint8 CMenuManager::GetNumberOfMenuOptions()
 {
@@ -3723,12 +5629,12 @@ uint8 CMenuManager::GetNumberOfMenuOptions()
 }
 #endif
 
+#undef GetBackJustUp
+#undef GetBackJustDown
+
 STARTPATCHES
-#if DONT_USE_SUSPICIOUS_FUNCS
-#else
 	for (int i = 1; i < ARRAY_SIZE(aScreens); i++)
 		Patch(0x611930 + sizeof(CMenuScreen) * i, aScreens[i]);
-#endif
 	InjectHook(0x4856F0, &CMenuManager::ProcessButtonPresses, PATCH_JUMP);
 	InjectHook(0x485100, &CMenuManager::Process, PATCH_JUMP);
 	InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP);
@@ -3741,4 +5647,5 @@ STARTPATCHES
 	InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP);
 	InjectHook(0x48AB40, &CMenuManager::DoSettingsBeforeStartingAGame, PATCH_JUMP);
 	InjectHook(0x48AE60, &CMenuManager::ProcessOnOffMenuOptions, PATCH_JUMP);
+	InjectHook(0x489710, &CMenuManager::DrawControllerBound, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 74b3990e..792f0c45 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -7,27 +7,10 @@
 #define MENUHEADER_WIDTH 0.84f
 #define MENUHEADER_HEIGHT 1.6f
 
-#define MENUACTION_X_MARGIN 40.0f
+#define MENU_X_MARGIN 40.0f
 #define MENUACTION_POS_Y 60.0f
-#define MENUACTION_WIDTH 0.405f
-#define MENUACTION_HEIGHT 0.63f
-
-#define MENUCOLUMN_POS_X MENUHEADER_POS_X + 16.0f
-#define MENUCOLUMN_MAX_Y 149.0f
-#define MENUCOLUMN_MID_Y 100.0f
-#define MENUCOLUMN_MIN_Y 110.0f
-#define MENUCOLUMN_PAUSE_Y 25.0f
-#define MENUCOLUMN_START_Y 9.0f
-#define MENUCOLUMN_FEDS 139.0f
-
-#define MENUCOLUMN_SAVE_X 121.0f
-#define MENUCOLUMN_SAVE_Y 111.0f
-
-#define MENUCOLUMN_SPACING_MAX 24.0f
-#define MENUCOLUMN_SPACING_MIN 20.0f
-
-#define MENUSELECT_BOX_MAX 20.5f
-#define MENUSELECT_BOX_MIN 17.0f
+#define MENUACTION_WIDTH 38.0f
+#define MENUACTION_SCALE_MULT 0.9f
 
 #ifndef ASPECT_RATIO_SCALE
 #define MENURADIO_ICON_X 31.5f
@@ -38,12 +21,63 @@
 #define MENURADIO_ICON_W 60.0f
 #define MENURADIO_ICON_H 60.0f
 
-#define MENUDROP_COLOR_A 150
-#define MENUDROP_COLOR_SIZE -1
-
 #define MENUSLIDER_X 256.0f
 #define MENUSLIDER_UNK 256.0f
 
+#define BIGTEXT_X_SCALE 0.75f
+#define BIGTEXT_Y_SCALE 0.9f
+#define MEDIUMTEXT_X_SCALE 0.55f
+#define MEDIUMTEXT_Y_SCALE 0.8f
+#define SMALLTEXT_X_SCALE 0.45f
+#define SMALLTEXT_Y_SCALE 0.7f
+#define SMALLESTTEXT_X_SCALE 0.4f
+#define SMALLESTTEXT_Y_SCALE 0.6f
+
+#define PLAYERSETUP_LIST_TOP 28.0f
+#define PLAYERSETUP_LIST_BOTTOM 125.0f
+#define PLAYERSETUP_LIST_LEFT 200.0f
+#define PLAYERSETUP_LIST_RIGHT 36.0f
+#ifdef FIX_BUGS // See the scrollbar button drawing code
+#define PLAYERSETUP_SCROLLBAR_WIDTH 19.0f
+#else
+#define PLAYERSETUP_SCROLLBAR_WIDTH 16.0f
+#endif
+#define PLAYERSETUP_SCROLLBUTTON_HEIGHT 17.0f
+#define PLAYERSETUP_SCROLLBUTTON_TXD_DIMENSION 64
+#define PLAYERSETUP_ROW_TEXT_X_SCALE 0.4f
+#define PLAYERSETUP_ROW_TEXT_Y_SCALE 0.6f
+#define PLAYERSETUP_SKIN_COLUMN_LEFT 220.0f
+#define PLAYERSETUP_DATE_COLUMN_RIGHT 56.0f
+#define PLAYERSETUP_LIST_BODY_TOP 47
+#define PLAYERSETUP_ROW_HEIGHT 9
+
+#define STATS_SLIDE_Y_PER_SECOND 30.0f
+#define STATS_ROW_HEIGHT 20.0f
+#define STATS_ROW_X_MARGIN 50.0f
+#define STATS_BOTTOM_MARGIN 135.0f
+#define STATS_TOP_MARGIN 40.0f
+#define STATS_TOP_DIMMING_AREA_LENGTH (93.0f - STATS_TOP_MARGIN)
+#define STATS_BOTTOM_DIMMING_AREA_LENGTH 55.0f
+#define STATS_PUT_BACK_TO_BOTTOM_Y 50.0f
+#define STATS_RATING_X 24.0f
+#define STATS_RATING_Y 20.0f
+
+#define CONTSETUP_STANDARD_ROW_HEIGHT 10.7f
+#define CONTSETUP_CLASSIC_ROW_HEIGHT 9.0f
+#define CONTSETUP_BOUND_HIGHLIGHT_HEIGHT 10
+#define CONTSETUP_BOUND_COLUMN_WIDTH 190.0f
+#define CONTSETUP_LIST_HEADER_HEIGHT 20.0f
+#define CONTSETUP_LIST_TOP 28.0f
+#define CONTSETUP_LIST_RIGHT 18.0f
+#define CONTSETUP_LIST_BOTTOM 120.0f
+#define CONTSETUP_LIST_LEFT 18.0f
+#define CONTSETUP_COLUMN_1_X 40.0f
+#define CONTSETUP_COLUMN_2_X 210.0f
+#define CONTSETUP_COLUMN_3_X (CONTSETUP_COLUMN_2_X + CONTSETUP_BOUND_COLUMN_WIDTH + 10.0f)
+#define CONTSETUP_BACK_RIGHT 35.0f
+#define CONTSETUP_BACK_BOTTOM 122.0f
+#define CONTSETUP_BACK_HEIGHT 25.0f
+
 enum eLanguages
 {
 	LANGUAGE_AMERICAN,
@@ -87,6 +121,8 @@ enum eFrontendSprites
 	FE_RADIO7,
 	FE_RADIO8,
 	FE_RADIO9,
+
+	NUM_FE_SPRITES
 };
 
 enum eMenuSprites
@@ -110,6 +146,8 @@ enum eMenuSprites
 	MENUSPRITE_UPOFF,
 	MENUSPRITE_UPON,
 	MENUSPRITE_GTA3LOGO,
+	MENUSPRITE_UNUSED,
+	NUM_MENU_SPRITES
 };
 
 enum eSaveSlot
@@ -127,6 +165,22 @@ enum eSaveSlot
 	SAVESLOT_LABEL = 36
 };
 
+#ifdef MENU_MAP
+enum MapSprites
+{
+	MAPMID1,
+	MAPMID2,
+	MAPMID3,
+	MAPBOT1,
+	MAPBOT2,
+	MAPBOT3,
+	MAPTOP1,
+	MAPTOP2,
+	MAPTOP3,
+	NUM_MAP_SPRITES
+};
+#endif
+
 enum eMenuScreen
 {
 	MENUPAGE_DISABLED = -1,
@@ -143,19 +197,19 @@ enum eMenuScreen
 	MENUPAGE_NEW_GAME_RELOAD = 10,
 	MENUPAGE_LOAD_SLOT_CONFIRM = 11,
 	MENUPAGE_DELETE_SLOT_CONFIRM = 12,
-	MENUPAGE_13 = 13,
+	MENUPAGE_NO_MEMORY_CARD = 13, // hud adjustment page in mobile
 	MENUPAGE_LOADING_IN_PROGRESS = 14,
 	MENUPAGE_DELETING_IN_PROGRESS = 15,
-	MENUPAGE_16 = 16,
+	MENUPAGE_PS2_LOAD_FAILED = 16,
 	MENUPAGE_DELETE_FAILED = 17,
 	MENUPAGE_DEBUG_MENU = 18,
-	MENUPAGE_MEMORY_CARD_1 = 19,
-	MENUPAGE_MEMORY_CARD_2 = 20,
+	MENUPAGE_MEMORY_CARD_DEBUG = 19,
+	MENUPAGE_MEMORY_CARD_TEST = 20,
 	MENUPAGE_MULTIPLAYER_MAIN = 21,
-	MENUPAGE_SAVE_FAILED_1 = 22,
-	MENUPAGE_SAVE_FAILED_2 = 23,
+	MENUPAGE_PS2_SAVE_FAILED = 22,
+	MENUPAGE_PS2_SAVE_FAILED_2 = 23,
 	MENUPAGE_SAVE = 24,
-	MENUPAGE_NO_MEMORY_CARD = 25,
+	MENUPAGE_NO_MEMORY_CARD_2 = 25,
 	MENUPAGE_CHOOSE_SAVE_SLOT = 26,
 	MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27,
 	MENUPAGE_MULTIPLAYER_MAP = 28,
@@ -187,8 +241,11 @@ enum eMenuScreen
 	MENUPAGE_SKIN_SELECT = 54,
 	MENUPAGE_KEYBOARD_CONTROLS = 55,
 	MENUPAGE_MOUSE_CONTROLS = 56,
-	MENUPAGE_57 = 57,
+	MENUPAGE_57 = 57, // mission failed, wanna restart page in mobile
 	MENUPAGE_58 = 58,
+#ifdef MENU_MAP
+	MENUPAGE_MAP = 59,
+#endif
 	MENUPAGES
 };
 
@@ -322,7 +379,7 @@ enum eCheckHover
 	HOVEROPTION_6,
 	HOVEROPTION_7,
 	HOVEROPTION_8,
-	HOVEROPTION_BACK,	// used in controller setup
+	HOVEROPTION_BACK,	// also layer in controller setup and skin menu
 	HOVEROPTION_10,
 	HOVEROPTION_11,
 	HOVEROPTION_OVER_SCROLL_UP,
@@ -332,9 +389,9 @@ enum eCheckHover
 	HOVEROPTION_HOLDING_SCROLLBAR,
 	HOVEROPTION_PAGEUP,
 	HOVEROPTION_PAGEDOWN,
-	HOVEROPTION_19,
-	HOVEROPTION_20,
-	HOVEROPTION_CHANGESKIN,
+	HOVEROPTION_LIST, // also layer in controller setup and skin menu
+	HOVEROPTION_SKIN,
+	HOVEROPTION_USESKIN, // also layer in controller setup and skin menu
 	HOVEROPTION_RADIO_0,
 	HOVEROPTION_RADIO_1,
 	HOVEROPTION_RADIO_2,
@@ -369,13 +426,20 @@ enum eControlMethod
 	CONTROL_CLASSIC,
 };
 
+// Why??
+enum ControllerSetupColumn
+{
+	CONTSETUP_PED_COLUMN = 0,
+	CONTSETUP_VEHICLE_COLUMN = 14,
+};
+
 struct tSkinInfo
 {
-	int32 field_0;
-	char skinName[256];
-	char currSkinName[256];
+	int32 skinId;
+	char skinNameDisplayed[256];
+	char skinNameOriginal[256];
 	char date[256];
-	tSkinInfo *field_304;
+	tSkinInfo *nextSkin;
 };
 
 struct BottomBarOption
@@ -387,7 +451,7 @@ struct BottomBarOption
 struct CMenuScreen
 {
 	char m_ScreenName[8];
-	int32 unk;
+	int32 unk; // 2 on MENUPAGE_MULTIPLAYER_START, 1 on everywhere else
 	int32 m_PreviousPage[2]; // eMenuScreen
 	int32 m_ParentEntry[2]; // row
 
@@ -413,7 +477,7 @@ public:
 	bool m_bMenuActive;
 	bool m_bMenuStateChanged;
 	bool m_bWaitingForNewKeyBind;
-	bool m_bStartGameLoading;
+	bool m_bWantToRestart;
 	bool m_bFirstTime;
 	bool m_bGameNotLoaded;
 	int32 m_nMousePosX;
@@ -421,24 +485,24 @@ public:
 	int32 m_nMouseTempPosX;
 	int32 m_nMouseTempPosY;
 	bool m_bShowMouse;
-	tSkinInfo m_sSkin;
+	tSkinInfo m_pSkinListHead;
 	tSkinInfo *m_pSelectedSkin;
 	int32 m_nFirstVisibleRowOnList;
-	float m_nCurListItemY;
+	float m_nScrollbarTopMargin;
 	int32 m_nTotalListRow;
 	int32 m_nSkinsTotal;
  char _unk0[4];
 	int32 m_nSelectedListRow;
-	bool m_bSkinsFound;
+	bool m_bSkinsEnumerated;
 	bool m_bQuitGameNoCD;
  bool m_bRenderGameInMenu;
 	bool m_bSaveMenuActive;
-	bool m_bLoadingSavedGame;
+	bool m_bWantToLoad;
  char field_455;
 	bool m_bStartWaitingForKeyBind;
 	bool m_bSpritesLoaded;
-	CSprite2d m_aFrontEndSprites[28];
-	CSprite2d m_aMenuSprites[20];
+	CSprite2d m_aFrontEndSprites[NUM_FE_SPRITES];
+	CSprite2d m_aMenuSprites[NUM_MENU_SPRITES];
  int32 field_518;
 	int32 m_nMenuFadeAlpha;
 	bool m_bPressedPgUpOnList;
@@ -448,10 +512,10 @@ public:
 	bool m_bPressedScrollButton;
 	int32 m_CurrCntrlAction;
  char _unk1[4];
- int32 field_530;
+ int32 m_nSelectedContSetupColumn;
 	 bool m_bKeyIsOK;
  bool field_535;
-	int8 m_nCurrExLayer;	// TODO: What's that?
+	int8 m_nCurrExLayer;
 	int32 m_nHelperTextAlpha;
 	int32 m_nMouseOldPosX;
 	int32 m_nMouseOldPosY;
@@ -468,47 +532,58 @@ public:
 	bool GetIsMenuActive() {return !!m_bMenuActive;}
 
 public:
-	static int32 &OS_Language;
-	static int8 &m_PrefsUseVibration;
-	static int8 &m_DisplayControllerOnFoot;
-	static int8 &m_PrefsUseWideScreen;
-	static int8 &m_PrefsRadioStation;
-	static int8 &m_PrefsVsync;
-	static int8 &m_PrefsVsyncDisp;
-	static int8 &m_PrefsFrameLimiter;
-	static int8 &m_PrefsShowSubtitles;
-	static int8 &m_PrefsSpeakers;
-	static int32 &m_ControlMethod;
-	static int8 &m_PrefsDMA;
-	static int32 &m_PrefsLanguage;
-	static int32 &m_PrefsBrightness;
-	static float &m_PrefsLOD;
-	static int8 &m_bFrontEnd_ReloadObrTxtGxt;
-	static int32 &m_PrefsMusicVolume;
-	static int32 &m_PrefsSfxVolume;
-	static char *m_PrefsSkinFile;
-	static int32 &m_KeyPressedCode;
+	static int32 OS_Language;
+	static int8 m_PrefsUseVibration;
+	static int8 m_DisplayControllerOnFoot;
+	static int8 m_PrefsUseWideScreen;
+	static int8 m_PrefsRadioStation;
+	static int8 m_PrefsVsync;
+	static int8 m_PrefsVsyncDisp;
+	static int8 m_PrefsFrameLimiter;
+	static int8 m_PrefsShowSubtitles;
+	static int8 m_PrefsSpeakers;
+	static int32 m_ControlMethod;
+	static int8 m_PrefsDMA;
+	static int32 m_PrefsLanguage;
+	static int32 m_PrefsBrightness;
+	static float m_PrefsLOD;
+	static int8 m_bFrontEnd_ReloadObrTxtGxt;
+	static int32 m_PrefsMusicVolume;
+	static int32 m_PrefsSfxVolume;
+	static char m_PrefsSkinFile[256];
+	static int32 m_KeyPressedCode;
 
-	static bool &m_bStartUpFrontEndRequested;
-	static bool &m_bShutDownFrontEndRequested;
-	static bool &m_PrefsAllowNastyGame;
+	static bool m_bStartUpFrontEndRequested;
+	static bool m_bShutDownFrontEndRequested;
+	static bool m_PrefsAllowNastyGame;
 	
-	static float &menuXYpadding;
-	static float &actionTextScaleX;
-	static float &actionTextScaleY;
-	static int32 &sthWithButtons;
-	static int32 &sthWithButtons2;
+	static uint8 m_PrefsStereoMono;
+	static int32 m_SelectedMap;
+	static int32 m_SelectedGameType;
+	static uint8 m_PrefsPlayerRed;
+	static uint8 m_PrefsPlayerGreen;
+	static uint8 m_PrefsPlayerBlue;
 
-#ifndef MASTER
-	static bool m_PrefsMarketing;
-	static bool m_PrefsDisableTutorials;
-#endif // !MASTER
+#ifndef MASTER
+	static bool m_PrefsMarketing;
+	static bool m_PrefsDisableTutorials;
+#endif // !MASTER
 
+#ifdef MENU_MAP
+	static bool bMenuMapActive;
+	static bool bMapMouseShownOnce;
+	static bool bMapLoaded;
+	static float fMapSize;
+	static float fMapCenterY;
+	static float fMapCenterX;
+	static CSprite2d m_aMapSprites[NUM_MAP_SPRITES];
+	void PrintMap();
+#endif
 
 public:
-	static void BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2);
+	static void BuildStatLine(char *text, void *stat, bool itsFloat, void *stat2);
 	static void CentreMousePointer();
-	int CheckCodesForControls(int32);
+	void CheckCodesForControls(int);
 	bool CheckHover(int x1, int x2, int y1, int y2);
 	void CheckSliderMovement(int);
 	int CostructStatLine(int);
@@ -516,7 +591,7 @@ public:
 	int DisplaySlider(float, float, float, float, float, float);
 	void DoSettingsBeforeStartingAGame();
 	void Draw();
-	void DrawControllerBound(int, int, int, uint8);
+	void DrawControllerBound(int32, int32, int32, int8);
 	void DrawControllerScreenExtraText(int, int, int);
 	void DrawControllerSetupScreen();
 	void DrawFrontEnd();
@@ -526,13 +601,13 @@ public:
 #endif
 	void DrawPlayerSetupScreen();
 	int FadeIn(int alpha);
-	void FilterOutColorMarkersFromString(uint16, CRGBA &);
+	void FilterOutColorMarkersFromString(wchar*, CRGBA &);
 	int GetStartOptionsCntrlConfigScreens();
 	static void InitialiseChangedLanguageSettings();
 	void LoadAllTextures();
 	void LoadSettings();
-	static void MessageScreen(char *);
-	static void PickNewPlayerColour();
+	void MessageScreen(const char *);
+	void PickNewPlayerColour();
 	void PrintBriefs();
 	static void PrintErrorMessage();
 	void PrintStats();
@@ -552,6 +627,8 @@ public:
 	void UnloadTextures();
 	void WaitForUserCD();
 	void PrintController();
+	int GetNumOptionsCntrlConfigScreens();
+	int ConstructStatLine(int);
 
 	// New (not in function or inlined in the game)
 	void ThingsToDoBeforeLeavingPage();
@@ -565,4 +642,4 @@ public:
 
 static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");
 
-extern CMenuManager &FrontEndMenuManager;
+extern CMenuManager FrontEndMenuManager;
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index 8571e93e..daac3ec5 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -89,8 +89,6 @@
 
 
 
-#define DEFAULT_VIEWWINDOW (0.7f)
-
 eLevelName &CGame::currLevel = *(eLevelName*)0x941514;
 bool &CGame::bDemoMode = *(bool*)0x5F4DD0;
 bool &CGame::nastyGame = *(bool*)0x5F4DD4;
@@ -492,7 +490,7 @@ void CGame::ReInitGameObjectVariables(void)
 	CParticle::ReloadConfig();
 	CCullZones::ResolveVisibilities();
 
-	if ( !FrontEndMenuManager.m_bLoadingSavedGame )
+	if ( !FrontEndMenuManager.m_bWantToLoad )
 	{
 		CCranes::InitCranes();
 		CTheScripts::StartTestScript();
@@ -566,7 +564,7 @@ void CGame::InitialiseWhenRestarting(void)
 	
 	TheCamera.Init();
 	
-	if ( FrontEndMenuManager.m_bLoadingSavedGame == true )
+	if ( FrontEndMenuManager.m_bWantToLoad == true )
 	{
 		RestoreForStartLoad();
 		CStreaming::LoadScene(TheCamera.GetPosition());
@@ -574,7 +572,7 @@ void CGame::InitialiseWhenRestarting(void)
 	
 	ReInitGameObjectVariables();
 	
-	if ( FrontEndMenuManager.m_bLoadingSavedGame == true )
+	if ( FrontEndMenuManager.m_bWantToLoad == true )
 	{
 		if ( GenericLoad() == true )
 		{
@@ -593,7 +591,7 @@ void CGame::InitialiseWhenRestarting(void)
 			ShutDownForRestart();
 			CTimer::Stop();
 			CTimer::Initialise();
-			FrontEndMenuManager.m_bLoadingSavedGame = false;
+			FrontEndMenuManager.m_bWantToLoad = false;
 			ReInitGameObjectVariables();
 			currLevel = LEVEL_INDUSTRIAL;
 			CCollision::SortOutCollisionAfterLoad();
@@ -609,6 +607,9 @@ extern void (*DebugMenuProcess)(void);
 void CGame::Process(void) 
 {
 	CPad::UpdatePads();
+#ifdef GTA_PS2
+	ProcessTidyUpMemory();
+#endif
 	TheCamera.SetMotionBlurAlpha(0);
 	if (TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_SNIPER || TheCamera.m_BlurType == MBLUR_NORMAL)
 		TheCamera.SetMotionBlur(0, 0, 0, 0, MBLUR_NONE);
@@ -695,6 +696,13 @@ void CGame::TidyUpMemory(bool, bool)
 #endif
 }
 
+void CGame::ProcessTidyUpMemory(void)
+{
+#ifdef PS2
+	// meow
+#endif
+}
+
 STARTPATCHES
 	InjectHook(0x48BB80, CGame::InitialiseOnceBeforeRW, PATCH_JUMP);
 	InjectHook(0x48BBA0, CGame::InitialiseRenderWare, PATCH_JUMP);
diff --git a/src/core/Game.h b/src/core/Game.h
index 318ff54b..30581893 100644
--- a/src/core/Game.h
+++ b/src/core/Game.h
@@ -39,4 +39,5 @@ public:
 	// NB: these do something on PS2
 	static void TidyUpMemory(bool, bool);
 	static void DrasticTidyUpMemory(bool);
+	static void ProcessTidyUpMemory(void);
 };
diff --git a/src/core/MenuScreens.h b/src/core/MenuScreens.h
index 45c5e5d6..8ce2d313 100644
--- a/src/core/MenuScreens.h
+++ b/src/core/MenuScreens.h
@@ -1,18 +1,22 @@
 #pragma once
 
-// There are some missing/wrong entries in here.
+// TODO: There are some missing/wrong entries in here.
 
 const CMenuScreen aScreens[] = {
 	// MENUPAGE_NONE = 0
-	{ "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, },
+	{ "", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, },
 
-	// MENUPAGE_STATS = 1 - Both PrintStats and Draw were printing the page name, so deleted the string Draw looked for.
-	{ ""/*"FET_STA"*/, MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2,
+	// MENUPAGE_STATS = 1
+#ifdef MENU_MAP
+	{ "FET_STA", 1, MENUPAGE_NONE, MENUPAGE_NONE, 5, 3,
+#else
+	{ "FET_STA", 1, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2,
+#endif
 		MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
 	// MENUPAGE_NEW_GAME = 2
-	{ "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 0, 1,
+	{ "FET_SGA", 1, MENUPAGE_NONE, MENUPAGE_NONE, 0, 1,
 		MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD,
 		MENUACTION_POPULATESLOTS_CHANGEMENU, "GMLOAD",  SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
 		MENUACTION_POPULATESLOTS_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
@@ -20,12 +24,16 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_BRIEFS = 3
-	{ "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 6, 3,
+#ifdef MENU_MAP
+	{ "FET_BRE", 1, MENUPAGE_NONE, MENUPAGE_NONE, 6, 4,
+#else
+	{ "FET_BRE", 1, MENUPAGE_NONE, MENUPAGE_NONE, 6, 3,
+#endif
 		MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
 	// MENU_CONTROLLER_SETTINGS = 4
-	{ "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
+	{ "FET_CON", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
 		MENUACTION_CTRLCONFIG,		"FEC_CCF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS,
 		MENUACTION_CTRLDISPLAY,		"FEC_CDP", SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS,
 		MENUACTION_CTRLVIBRATION,	"FEC_VIB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS,
@@ -33,7 +41,7 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_SOUND_SETTINGS = 5
-	{ "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 1, 1,
+	{ "FET_AUD", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 1, 1,
 		MENUACTION_MUSICVOLUME,		"FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
 		MENUACTION_SFXVOLUME,		"FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
 		MENUACTION_AUDIOHW,			"FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
@@ -45,7 +53,7 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_GRAPHICS_SETTINGS = 6
-	{ "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 2, 2,
+	{ "FET_DIS", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 2, 2,
 		MENUACTION_BRIGHTNESS,	"FED_BRI", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
 		MENUACTION_DRAWDIST,	"FEM_LOD", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
 		MENUACTION_FRAMESYNC,	"FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
@@ -59,7 +67,7 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_LANGUAGE_SETTINGS = 7
-	{ "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 3, 3,
+	{ "FET_LAN", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 3, 3,
 		MENUACTION_LANG_ENG,	"FEL_ENG", SAVESLOT_NONE, MENUPAGE_NONE,
 		MENUACTION_LANG_FRE,	"FEL_FRE", SAVESLOT_NONE, MENUPAGE_NONE,
 		MENUACTION_LANG_GER,	"FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE,
@@ -73,7 +81,7 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_CHOOSE_LOAD_SLOT = 8
-	{ "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 1, 1,
+	{ "FET_LG", 1, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 1, 1,
 		MENUACTION_CHANGEMENU,	"FESZ_CA", SAVESLOT_NONE,	MENUPAGE_NEW_GAME,
 		MENUACTION_CHECKSAVE,	"FEM_SL1", SAVESLOT_1,		MENUPAGE_LOAD_SLOT_CONFIRM,
 		MENUACTION_CHECKSAVE,	"FEM_SL2", SAVESLOT_2,		MENUPAGE_LOAD_SLOT_CONFIRM,
@@ -86,7 +94,7 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_CHOOSE_DELETE_SLOT = 9
-	{ "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 2, 2,
+	{ "FET_DG", 1, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 2, 2,
 		MENUACTION_CHANGEMENU,	"FESZ_CA",	SAVESLOT_NONE,	MENUPAGE_NEW_GAME,
 		MENUACTION_CHECKSAVE,	"FEM_SL1",	SAVESLOT_1,		MENUPAGE_DELETE_SLOT_CONFIRM,
 		MENUACTION_CHECKSAVE,	"FEM_SL2",	SAVESLOT_2,		MENUPAGE_DELETE_SLOT_CONFIRM,
@@ -99,104 +107,123 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_NEW_GAME_RELOAD = 10
-	{ "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 0, 0,
+	{ "FET_NG", 1, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, 0, 0,
 		MENUACTION_LABEL,		"FESZ_QR",	SAVESLOT_NONE,	MENUPAGE_NONE,
 		MENUACTION_CHANGEMENU,	"FEM_NO",	SAVESLOT_NONE,	MENUPAGE_NEW_GAME,
 		MENUACTION_NEWGAME,		"FEM_YES",	SAVESLOT_NONE,	MENUPAGE_NEW_GAME_RELOAD,
 	},
 
 	// MENUPAGE_LOAD_SLOT_CONFIRM = 11
-	{ "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, 0, 0,
+	{ "FET_LG", 1, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, 0, 0,
 		 MENUACTION_LABEL,		"FESZ_QL",	SAVESLOT_NONE,	MENUPAGE_NONE,
 		 MENUACTION_CHANGEMENU,	"FEM_NO",	SAVESLOT_NONE,	MENUPAGE_CHOOSE_LOAD_SLOT,
 		 MENUACTION_CHANGEMENU,	"FEM_YES",	SAVESLOT_NONE,	MENUPAGE_LOADING_IN_PROGRESS,
 	},
 
 	// MENUPAGE_DELETE_SLOT_CONFIRM = 12
-	{ "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
+	{ "FET_DG", 1, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
 		 MENUACTION_LABEL,		"FESZ_QD",	SAVESLOT_NONE,  MENUPAGE_NONE,
 		 MENUACTION_CHANGEMENU,	"FEM_NO",	SAVESLOT_NONE,  MENUPAGE_CHOOSE_DELETE_SLOT,
 		 MENUACTION_CHANGEMENU,	"FEM_YES",	SAVESLOT_NONE,	MENUPAGE_DELETING,
 	},
 
-	// MENUPAGE_13 = 13
-	{ "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
-
+	// MENUPAGE_NO_MEMORY_CARD = 13
+	{ "FES_NOC", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+		// hud adjustment page in mobile
 	},
 
 	// MENUPAGE_LOADING_IN_PROGRESS = 14
-	{ "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_LG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM,
 	},
 
 	// MENUPAGE_DELETING_IN_PROGRESS = 15
-	{ "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_DG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
-	// MENUPAGE_16 = 16
-	{ "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	// MENUPAGE_PS2_LOAD_FAILED = 16
+	{ "FET_LG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
 	// MENUPAGE_DELETE_FAILED = 17
-	{ "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_DG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_LABEL, "FES_DEE", SAVESLOT_NONE, MENUPAGE_NONE,
 		MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
 	},
 
 	// MENUPAGE_DEBUG_MENU = 18
-	{ "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
-
+	{ "FED_DBG", 1, MENUPAGE_NONE, MENUPAGE_NONE, 4, 0,
+		MENUACTION_RELOADIDE,	"FED_RID", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_RELOADIPL,	"FED_RIP", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_SETDBGFLAG,	"FED_DFL", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_SWITCHBIGWHITEDEBUGLIGHT,	"FED_DLS", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_PEDROADGROUPS,	"FED_SPR", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_CARROADGROUPS,	"FED_SCR", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_COLLISIONPOLYS,	"FED_SCP", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_PARSEHEAP,	"FED_PAH", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_SHOWCULL,	"FED_SCZ", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_DEBUGSTREAM,	"FED_DSR", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_CHANGEMENU,	"FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
-	// MENUPAGE_MEMORY_CARD_1 = 19
-	{ "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
-
+	// MENUPAGE_MEMORY_CARD_DEBUG = 19
+	{ "FEM_MCM", 1, MENUPAGE_NONE, MENUPAGE_NONE, 7, 0,
+		MENUACTION_REGMEMCARD1,	"FEM_RMC", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_TESTFORMATMEMCARD1,	"FEM_TFM", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_TESTUNFORMATMEMCARD1,	"FEM_TUM", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_CREATEROOTDIR,	"FEM_CRD", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_CREATELOADICONS,	"FEM_CLI", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_FILLWITHGUFF,	"FEM_FFF", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_SAVEONLYTHEGAME,	"FEM_SOG", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_SAVEGAME,	"FEM_STG", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_SAVEGAMEUNDERGTA,	"FEM_STS", SAVESLOT_NONE, MENUPAGE_NONE,
+		MENUACTION_CREATECOPYPROTECTED,	"FEM_CPD", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
-	// MENUPAGE_MEMORY_CARD_2 = 20
-	{ "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	// MENUPAGE_MEMORY_CARD_TEST = 20
+	{ "FEM_MC2", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_MULTIPLAYER_MAIN = 21
-	{ "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_MP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
-	// MENUPAGE_SAVE_FAILED_1 = 22
-	{ "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	// MENUPAGE_PS2_SAVE_FAILED = 22
+	{ "MCDNSP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
-	// MENUPAGE_SAVE_FAILED_2 = 23
-	{ "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	// MENUPAGE_PS2_SAVE_FAILED_2 = 23
+	{ "MCGNSP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
 	// Unused in PC but anyway
 	// MENUPAGE_SAVE = 24
 #ifdef PS2_SAVE_DIALOG
-	{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_SG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_CHANGEMENU,			"FESZ_SA",	SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
 		MENUACTION_RESUME_FROM_SAVEZONE,	"FESZ_CA",	SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 #else
-	{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_SG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_LABEL,				"FES_SCG",	SAVESLOT_NONE, MENUPAGE_NONE,
 		MENUACTION_POPULATESLOTS_CHANGEMENU,			"GMSAVE",	SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
 		MENUACTION_RESUME_FROM_SAVEZONE,	"FESZ_CA",	SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 #endif
 
-	// MENUPAGE_NO_MEMORY_CARD = 25
-	{ "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
-
+	// MENUPAGE_NO_MEMORY_CARD_2 = 25
+	{ "FES_NOC", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+		MENUACTION_CHANGEMENU,	"FESZ_CA",	SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
 	// MENUPAGE_CHOOSE_SAVE_SLOT = 26
-	{ "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_SG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		MENUACTION_RESUME_FROM_SAVEZONE,	"FESZ_CA", SAVESLOT_NONE,	MENUPAGE_NONE,
 		MENUACTION_CHANGEMENU,			"FEM_SL1", SAVESLOT_1,		MENUPAGE_SAVE_OVERWRITE_CONFIRM,
 		MENUACTION_CHANGEMENU,			"FEM_SL2", SAVESLOT_2,		MENUPAGE_SAVE_OVERWRITE_CONFIRM,
@@ -209,59 +236,58 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27
-	{ "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
+	{ "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
 		MENUACTION_LABEL,		"FESZ_QO", SAVESLOT_NONE, MENUPAGE_NONE,
 		MENUACTION_CHANGEMENU,	"FEM_YES", SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS,
 		MENUACTION_CHANGEMENU,	"FEM_NO",  SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
 	},
 
 	// MENUPAGE_MULTIPLAYER_MAP = 28
-	{ "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_MAP", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_MULTIPLAYER_CONNECTION = 29
-	{ "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_CON", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_MULTIPLAYER_FIND_GAME = 30
-	{ "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_FG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_MULTIPLAYER_MODE = 31
-	{ "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_GT", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_MULTIPLAYER_CREATE = 32
-	{ "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_HG", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_MULTIPLAYER_START = 33
-	{ "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FEN_STA", 2, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_SKIN_SELECT_OLD = 34
-	{ "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+	{ "FET_PS", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
 	},
 
 	// MENUPAGE_CONTROLLER_PC = 35
-	{ "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
+	{ "FET_CTL", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 0, 0,
 		MENUACTION_CTRLMETHOD,	"FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
 		MENUACTION_CHANGEMENU,	"FET_RDK", SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS,
 		MENUACTION_CHANGEMENU,	"FET_AMS", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
-
 		MENUACTION_RESTOREDEF,	"FET_DEF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
 		MENUACTION_CHANGEMENU,	"FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
 	},
 
 	// MENUPAGE_CONTROLLER_PC_OLD1 = 36
-	{ "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 0, 0,
+	{ "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 0, 0,
 		MENUACTION_GETKEY,	"FEC_PLB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
 		MENUACTION_GETKEY,	"FEC_CWL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
 		MENUACTION_GETKEY,	"FEC_CWR", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1,
@@ -275,12 +301,12 @@ const CMenuScreen aScreens[] = {
 	},
 
 	// MENUPAGE_CONTROLLER_PC_OLD2 = 37
-	{ "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1,
+	{ "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1,
 
 	},
 
 	// MENUPAGE_CONTROLLER_PC_OLD3 = 38
-   { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2,
+   { "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2,
 		MENUACTION_GETKEY,	"FEC_LUP", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3,
 		MENUACTION_GETKEY,	"FEC_LDN", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3,
 		MENUACTION_GETKEY,	"FEC_SMS", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3,
@@ -289,17 +315,25 @@ const CMenuScreen aScreens[] = {
    },
 
    // MENUPAGE_CONTROLLER_PC_OLD4 = 39
-   { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 3, 3,
+   { "FET_CTL", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 3, 3,
 
    },
 
    // MENUPAGE_CONTROLLER_DEBUG = 40
-   { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
-
+   { "FEC_DBG", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 3, 3,
+		MENUACTION_GETKEY,	"FEC_TGD",	SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
+		MENUACTION_GETKEY,	"FEC_TDO",	SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
+		MENUACTION_GETKEY,	"FEC_TSS",	SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
+		MENUACTION_GETKEY,	"FEC_SMS",	SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG,
+		MENUACTION_CHANGEMENU,	"FEDS_TB",	SAVESLOT_NONE, MENUPAGE_NONE,
    },
 
    // MENUPAGE_OPTIONS = 41
-   { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 1, 4,
+#ifdef MENU_MAP
+   { "FET_OPT", 1, MENUPAGE_NONE, MENUPAGE_NONE, 1, 5,
+#else
+   { "FET_OPT", 1, MENUPAGE_NONE, MENUPAGE_NONE, 1, 4,
+#endif
 		MENUACTION_CHANGEMENU,		"FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
 		MENUACTION_LOADRADIO,		"FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
 		MENUACTION_CHANGEMENU,		"FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
@@ -309,67 +343,74 @@ const CMenuScreen aScreens[] = {
    },
 
    // MENUPAGE_EXIT = 42
-   { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, 2, 5,
+#ifdef MENU_MAP
+   { "FET_QG", 1, MENUPAGE_NONE, MENUPAGE_NONE, 2, 6,
+#else
+   { "FET_QG", 1, MENUPAGE_NONE, MENUPAGE_NONE, 2, 5,
+#endif
 	   MENUACTION_LABEL,		"FEQ_SRE",	SAVESLOT_NONE, MENUPAGE_NONE,
 	   MENUACTION_CHANGEMENU,	"FEM_NO",	SAVESLOT_NONE, MENUPAGE_NONE,
 	   MENUACTION_CANCELGAME,	"FEM_YES",	SAVESLOT_NONE, MENUPAGE_NONE,
    },
 
    // MENUPAGE_SAVING_IN_PROGRESS = 43
-   { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
+   { "", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
 	   MENUACTION_LABEL,	"FES_WAR",	SAVESLOT_NONE, MENUPAGE_NONE,
    },
 
    // MENUPAGE_SAVE_SUCCESSFUL = 44
-   { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
+   { "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
 	   MENUACTION_LABEL,				"FES_SSC",	SAVESLOT_LABEL,	MENUPAGE_NONE,
 	   MENUACTION_RESUME_FROM_SAVEZONE,	"FEC_OKK",	SAVESLOT_NONE,	MENUPAGE_CHOOSE_SAVE_SLOT,
    },
 
    // MENUPAGE_DELETING = 45
-   { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
+   { "FET_DG", 1, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
 	   MENUACTION_LABEL,	"FED_DLW",	SAVESLOT_NONE, MENUPAGE_NONE,
    },
 
    // MENUPAGE_DELETE_SUCCESS = 46
-   { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
+   { "FET_DG", 1, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, 0, 0,
 		MENUACTION_LABEL,		"DEL_FNM", SAVESLOT_NONE,	MENUPAGE_NONE,
 		MENUACTION_CHANGEMENU,	"FEC_OKK", SAVESLOT_NONE,	MENUPAGE_CHOOSE_DELETE_SLOT,
    },
 
    // MENUPAGE_SAVE_FAILED = 47
-   { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
+   { "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
 		MENUACTION_LABEL,		"FEC_SVU",	SAVESLOT_NONE,	MENUPAGE_NONE,
 		MENUACTION_CHANGEMENU,	"FEC_OKK",	SAVESLOT_NONE,	MENUPAGE_CHOOSE_SAVE_SLOT,
    },
 
    // MENUPAGE_LOAD_FAILED = 48
-   { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
+   { "FET_SG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
 		MENUACTION_LABEL,	"FEC_SVU",	SAVESLOT_NONE,	MENUPAGE_NONE,
    },
 
    // MENUPAGE_LOAD_FAILED_2 = 49
-   { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
+   { "FET_LG", 1, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, 0, 0,
 		MENUACTION_LABEL,		"FEC_LUN",	SAVESLOT_NONE,  MENUPAGE_NONE,
 		MENUACTION_CHANGEMENU,	"FEDS_TB",	SAVESLOT_NONE,  MENUPAGE_CHOOSE_LOAD_SLOT,
    },
 
    // MENUPAGE_FILTER_GAME = 50
-   { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+   { "FIL_FLT", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 
    },
 
    // MENUPAGE_START_MENU = 51
-   { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+   { "FEM_MM", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 		 MENUACTION_CHANGEMENU,	"FEN_STA",	SAVESLOT_NONE,	MENUPAGE_NEW_GAME,
 		 MENUACTION_CHANGEMENU,	"FET_OPT",	SAVESLOT_NONE,	MENUPAGE_OPTIONS,
 		 MENUACTION_CHANGEMENU,	"FEM_QT",	SAVESLOT_NONE,	MENUPAGE_EXIT,
    },
 
    // MENUPAGE_PAUSE_MENU = 52
-   { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+   { "FET_PAU", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
 	   MENUACTION_RESUME,		"FEM_RES",	SAVESLOT_NONE, MENUPAGE_NONE,
 	   MENUACTION_CHANGEMENU,	"FEN_STA",	SAVESLOT_NONE, MENUPAGE_NEW_GAME,
+#ifdef MENU_MAP
+	   MENUACTION_CHANGEMENU,	"FEG_MAP",	SAVESLOT_NONE, MENUPAGE_MAP,
+#endif
 	   MENUACTION_CHANGEMENU,	"FEP_STA",	SAVESLOT_NONE, MENUPAGE_STATS,
 	   MENUACTION_CHANGEMENU,	"FEP_BRI",	SAVESLOT_NONE, MENUPAGE_BRIEFS,
 	   MENUACTION_CHANGEMENU,	"FET_OPT",	SAVESLOT_NONE, MENUPAGE_OPTIONS,
@@ -377,22 +418,24 @@ const CMenuScreen aScreens[] = {
    },
 
    // MENUPAGE_CHOOSE_MODE = 53
-   { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
-
+   { "FEN_STA", 1, MENUPAGE_NONE, MENUPAGE_NONE, 0, 1,
+	   MENUACTION_CHANGEMENU,	"FET_SP",	SAVESLOT_NONE, MENUPAGE_NEW_GAME,
+	   MENUACTION_INITMP,		"FET_MP",	SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
+	   MENUACTION_CHANGEMENU,	"FEDS_TB",	SAVESLOT_NONE, MENUPAGE_NONE,
    },
 
    // MENUPAGE_SKIN_SELECT = 54
-   { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 4, 4,
-		MENUACTION_CHANGEMENU,		"FEDS_TB",	SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
+   { "FET_PSU", 1, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, 4, 4,
+		MENUACTION_CHANGEMENU,	"FEDS_TB",	SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
    },
 
    // MENUPAGE_KEYBOARD_CONTROLS = 55
-   { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1,
-		MENUACTION_CHANGEMENU,		"FEDS_TB",	SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+   { "FET_STI", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 1, 1,
+		MENUACTION_CHANGEMENU,	"FEDS_TB",	SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
    },
 
    // MENUPAGE_MOUSE_CONTROLS = 56
-   { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2,
+   { "FET_MTI", 1, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, 2, 2,
 	   MENUACTION_MOUSESENS,	"FEC_MSH",	SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
 	   MENUACTION_INVVERT,		"FEC_IVV",	SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
 	   MENUACTION_MOUSESTEER,	"FET_MST",	SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
@@ -400,12 +443,18 @@ const CMenuScreen aScreens[] = {
    },
 
    // MENUPAGE_57 = 57
-   { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
-
+   { "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0,
+	   // mission failed, wanna restart page in mobile
    },
 
    // MENUPAGE_58 = 58
-   { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0,
+   { "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0,
 
    },
+
+#ifdef MENU_MAP
+   // MENUPAGE_MAP = 59
+   { "FEG_MAP", 1, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2,
+   },
+#endif
 };
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index 6bbe00f2..f83998b8 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -21,19 +21,26 @@
 #include "Hud.h"
 #include "Text.h"
 #include "Timer.h"
+#include "Record.h"
 #include "World.h"
 #include "Vehicle.h"
 #include "Ped.h"
 #include "Population.h"
+#include "Record.h"
 #include "Replay.h"
 #include "Weather.h"
 #include "win.h"
+#include "Streaming.h"
+#include "PathFind.h"
+#include "Wanted.h"
+#include "General.h"
 
 CPad *Pads = (CPad*)0x6F0360; // [2]
 CMousePointerStateHelper &MousePointerStateHelper = *(CMousePointerStateHelper*)0x95CC8C;
 
 bool &CPad::bDisplayNoControllerMessage = *(bool *)0x95CD52;
 bool &CPad::bObsoleteControllerMessage = *(bool *)0x95CDB8;
+bool CPad::bOldDisplayNoControllerMessage;
 bool &CPad::m_bMapPadOneToPadTwo = *(bool *)0x95CD48;
 
 CKeyboardState &CPad::OldKeyState = *(CKeyboardState*)0x6F1E70;
@@ -49,29 +56,217 @@ CMouseControllerState &CPad::PCTempMouseControllerState = *(CMouseControllerStat
 _TODO("gbFastTime");
 extern bool &gbFastTime;
 
-WRAPPER void WeaponCheat() { EAXJMP(0x490D90); }
-WRAPPER void HealthCheat() { EAXJMP(0x490E70); }
-WRAPPER void TankCheat() { EAXJMP(0x490EE0); }
-WRAPPER void BlowUpCarsCheat() { EAXJMP(0x491040); }
-WRAPPER void ChangePlayerCheat() { EAXJMP(0x4910B0); }
-WRAPPER void MayhemCheat() { EAXJMP(0x4911C0); }
-WRAPPER void EverybodyAttacksPlayerCheat() { EAXJMP(0x491270); }
-WRAPPER void WeaponsForAllCheat() { EAXJMP(0x491370); }
-WRAPPER void FastTimeCheat() { EAXJMP(0x4913A0); }
-WRAPPER void SlowTimeCheat() { EAXJMP(0x4913F0); }
-WRAPPER void MoneyCheat() { EAXJMP(0x491430); }
-WRAPPER void ArmourCheat() { EAXJMP(0x491460); }
-WRAPPER void WantedLevelUpCheat() { EAXJMP(0x491490); }
-WRAPPER void WantedLevelDownCheat() { EAXJMP(0x4914F0); }
-WRAPPER void SunnyWeatherCheat() { EAXJMP(0x491520); }
-WRAPPER void CloudyWeatherCheat() { EAXJMP(0x491550); }
-WRAPPER void RainyWeatherCheat() { EAXJMP(0x491580); }
-WRAPPER void FoggyWeatherCheat() { EAXJMP(0x4915B0); }
-WRAPPER void FastWeatherCheat() { EAXJMP(0x4915E0); }
-WRAPPER void OnlyRenderWheelsCheat() { EAXJMP(0x491610); }
-WRAPPER void ChittyChittyBangBangCheat() { EAXJMP(0x491640); }
-WRAPPER void StrongGripCheat() { EAXJMP(0x491670); }
-WRAPPER void NastyLimbsCheat() { EAXJMP(0x4916A0); }
+void WeaponCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT2"), true);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_BASEBALLBAT, 0);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_COLT45, 100);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_UZI, 100);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_SHOTGUN, 20);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_AK47, 200);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_M16, 200);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_SNIPERRIFLE, 5);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_ROCKETLAUNCHER, 5);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_MOLOTOV, 5);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_GRENADE, 5);
+	FindPlayerPed()->GiveWeapon(WEAPONTYPE_FLAMETHROWER, 200);
+}
+
+void HealthCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT3"), true);
+	FindPlayerPed()->m_fHealth = 100.0f;
+	if (FindPlayerVehicle()) {
+		FindPlayerVehicle()->m_fHealth = 1000.0f;
+		if (FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_CAR)
+			((CAutomobile*)FindPlayerVehicle())->Damage.SetEngineStatus(0);
+	}
+}
+
+void TankCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	CStreaming::RequestModel(MI_RHINO, 0);
+	CStreaming::LoadAllRequestedModels(false);
+	if (CStreaming::ms_aInfoForModel[MI_RHINO].m_loadState == STREAMSTATE_LOADED) {
+		CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+		int32 node = ThePaths.FindNodeClosestToCoors(FindPlayerCoors(), PATH_CAR, 100.0f);
+
+		if (node < 0) return;
+		
+#ifdef FIX_BUGS
+		CAutomobile* tank = new CAutomobile(MI_RHINO, RANDOM_VEHICLE);
+#else
+		CAutomobile *tank = new CAutomobile(MI_RHINO, MISSION_VEHICLE);
+#endif
+		if (tank != nil) {
+			CVector pos = ThePaths.m_pathNodes[node].pos;
+			pos.z += 4.0f;
+			tank->GetPosition() = pos;
+			tank->SetOrientation(0.0f, 0.0f, DEGTORAD(200.0f));
+
+			tank->m_status = STATUS_ABANDONED;
+			tank->m_nDoorLock = CARLOCK_UNLOCKED;
+			CWorld::Add(tank);
+		}
+	}
+}
+
+void BlowUpCarsCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+
+	int i = CPools::GetVehiclePool()->GetSize();
+	while (i-- > 0) {
+		if (CVehicle *veh = CPools::GetVehiclePool()->GetSlot(i))
+			veh->BlowUpCar(nil);
+	}
+}
+
+void ChangePlayerCheat()
+{
+	int modelId;
+
+	if (FindPlayerPed()->IsPedInControl() && CModelInfo::GetModelInfo("player", nil)) {
+		CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+		CPlayerPed *ped = FindPlayerPed();
+		AssocGroupId AnimGrp = ped->m_animGroup;
+		do
+		{
+			do
+				modelId = CGeneral::GetRandomNumberInRange(0, MI_CAS_WOM+1);
+			while (!CModelInfo::GetModelInfo(modelId));
+		} while (modelId >= MI_SPECIAL01 && modelId <= MI_SPECIAL04 || modelId == MI_TAXI_D);
+
+		uint8 flags = CStreaming::ms_aInfoForModel[modelId].m_flags;
+		ped->DeleteRwObject();
+		CStreaming::RequestModel(modelId, STREAMFLAGS_DEPENDENCY| STREAMFLAGS_DONT_REMOVE);
+		CStreaming::LoadAllRequestedModels(false);
+		ped->m_modelIndex = -1;
+		ped->SetModelIndex(modelId);
+		ped->m_animGroup = AnimGrp;
+		if (modelId != MI_PLAYER) {
+			if (!(flags & STREAMFLAGS_DONT_REMOVE))
+				CStreaming::SetModelIsDeletable(modelId);
+		}
+	}
+}
+
+void MayhemCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	for (int i = PEDTYPE_CIVMALE; i < PEDTYPE_SPECIAL; i++)
+		CPedType::SetThreats(i, PED_FLAG_PLAYER1 | PED_FLAG_PLAYER2 | PED_FLAG_PLAYER3 | PED_FLAG_PLAYER4 |
+			PED_FLAG_CIVMALE | PED_FLAG_CIVFEMALE | PED_FLAG_COP | PED_FLAG_GANG1 |
+			PED_FLAG_GANG2 | PED_FLAG_GANG3 | PED_FLAG_GANG4 | PED_FLAG_GANG5 |
+			PED_FLAG_GANG6 | PED_FLAG_GANG7 | PED_FLAG_GANG8 | PED_FLAG_GANG9 |
+			PED_FLAG_EMERGENCY | PED_FLAG_PROSTITUTE | PED_FLAG_CRIMINAL | PED_FLAG_SPECIAL );
+}
+
+void EverybodyAttacksPlayerCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	for (int i = PEDTYPE_CIVMALE; i < PEDTYPE_SPECIAL; i++)
+		CPedType::AddThreat(i, PED_FLAG_PLAYER1);
+}
+
+void WeaponsForAllCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	CPopulation::ms_bGivePedsWeapons = !CPopulation::ms_bGivePedsWeapons;
+}
+
+void FastTimeCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	if (CTimer::GetTimeScale() < 4.0f)
+		CTimer::SetTimeScale(CTimer::GetTimeScale() * 2.0f);
+}
+
+void SlowTimeCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	if (CTimer::GetTimeScale() > 0.25f)
+		CTimer::SetTimeScale(CTimer::GetTimeScale() * 0.5f);
+}
+
+void MoneyCheat()
+{
+	CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 250000;
+	CHud::SetHelpMessage(TheText.Get("CHEAT6"), true);
+}
+
+void ArmourCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT4"), true);
+	FindPlayerPed()->m_fArmour = 100.0f;
+}
+
+void WantedLevelUpCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT5"), true);
+	FindPlayerPed()->SetWantedLevel(min(FindPlayerPed()->m_pWanted->m_nWantedLevel + 2, 6));
+}
+
+void WantedLevelDownCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT5"), true);
+	FindPlayerPed()->SetWantedLevel(0);
+}
+
+void SunnyWeatherCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT7"), true);
+	CWeather::ForceWeatherNow(WEATHER_SUNNY);
+}
+
+void CloudyWeatherCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT7"), true);
+	CWeather::ForceWeatherNow(WEATHER_CLOUDY);
+}
+
+void RainyWeatherCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT7"), true);
+	CWeather::ForceWeatherNow(WEATHER_RAINY);
+}
+
+void FoggyWeatherCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT7"), true);
+	CWeather::ForceWeatherNow(WEATHER_FOGGY);
+}
+
+void FastWeatherCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	gbFastTime = !gbFastTime;
+}
+
+void OnlyRenderWheelsCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	CVehicle::bWheelsOnlyCheat = !CVehicle::bWheelsOnlyCheat;
+}
+
+
+void ChittyChittyBangBangCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	CVehicle::bAllDodosCheat = !CVehicle::bAllDodosCheat;
+}
+
+void StrongGripCheat()
+{
+	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+	CVehicle::bCheat3 = !CVehicle::bCheat3;
+}
+
+void NastyLimbsCheat()
+{
+	CPed::bNastyLimbsCheat = !CPed::bNastyLimbsCheat;
+}
 //////////////////////////////////////////////////////////////////////////
 
 #ifdef KANGAROO_CHEAT
@@ -88,7 +283,7 @@ void KangarooCheat()
 		string = TheText.Get("CHEAT1");
 		m_fMass = 15.0f;
 	}
-	CHud::SetHelpMessage(string, 1);
+	CHud::SetHelpMessage(string, true);
 	playerPed->m_ped_flagI80 = !playerPed->m_ped_flagI80;
 
 	playerPed->m_fMass = m_fMass;
@@ -137,6 +332,21 @@ void CKeyboardState::Clear()
 	LWIN = RWIN = APPS = 0;
 }
 
+#ifdef GTA_PS2_STUFF
+void CPad::Initialise(void)
+{
+	for (int i = 0; i < MAX_PADS; i++)
+	{
+		CPad::GetPad(i)->Clear(true);
+		CPad::GetPad(i)->Mode = 0;
+	}
+	
+	bObsoleteControllerMessage     = false;
+	bOldDisplayNoControllerMessage = false;
+	bDisplayNoControllerMessage    = false;
+}
+#endif
+
 void CPad::Clear(bool bResetPlayerControls)
 {
 	NewState.Clear();
@@ -164,13 +374,13 @@ void CPad::Clear(bool bResetPlayerControls)
 	bApplyBrakes = false;
 	
 	
-	for ( int32 i = 0; i < _TODOCONST(5); i++ )
+	for ( int32 i = 0; i < HORNHISTORY_SIZE; i++ )
 		bHornHistory[i] = false;
 	
 	iCurrHornHistory = 0;
 	
-	for ( int32 i = 0; i < _TODOCONST(12); i++ )
-		_unk[i] = ' ';
+	for ( int32 i = 0; i < ARRAY_SIZE(CheatString); i++ )
+		CheatString[i] = ' ';
 	
 	LastTimeTouched = CTimer::GetTimeInMilliseconds();
 	AverageWeapon = 0;
@@ -429,6 +639,108 @@ void CPad::StartShake_Train(float fX, float fY)
 	}
 }
 
+#ifdef GTA_PS2_STUFF
+void CPad::AddToCheatString(char c)
+{
+	for ( int32 i = ARRAY_SIZE(CheatString) - 2; i >= 0; i-- )
+		CheatString[i + 1] = CheatString[i];
+
+#define _CHEATCMP(str)  strncmp(str, CheatString, sizeof(str)-1)
+	// "4414LDRULDRU"	-	R2 R2 L1 R2 LEFT DOWN RIGHT UP LEFT DOWN RIGHT UP
+	if ( !_CHEATCMP("URDLURDL4144") )
+		WeaponCheat();
+
+	// "4411LDRULDRU"	-	R2 R2 L1 L1 LEFT DOWN RIGHT UP LEFT DOWN RIGHT UP
+	else if ( !_CHEATCMP("URDLURDL1144") )
+		MoneyCheat();
+	
+	// "4412LDRULDRU"	-	R2 R2 L1 L2 LEFT DOWN RIGHT UP LEFT DOWN RIGHT UP
+	else if ( !_CHEATCMP("URDLURDL2144") )
+		ArmourCheat();
+	
+	// "4413LDRULDRU"	-	R2 R2 L1 R1 LEFT DOWN RIGHT UP LEFT DOWN RIGHT UP
+	else if ( !_CHEATCMP("URDLURDL3144") )
+		HealthCheat();
+
+	// "4414LRLRLR"		-	R2 R2 L1 R2 LEFT RIGHT LEFT RIGHT LEFT RIGHT
+	else if ( !_CHEATCMP("RLRLRL4144") )
+		WantedLevelUpCheat();
+	
+	// "4414UDUDUD"		-	R2 R2 L1 R2 UP DOWN UP DOWN UP DOWN
+	else if ( !_CHEATCMP("DUDUDU4144") )
+		WantedLevelDownCheat();
+	
+	// "1234432T"		-	L1 L2 R1 R2 R2 R1 L2 TRIANGLE
+	else if ( !_CHEATCMP("T2344321") )
+		SunnyWeatherCheat();
+	
+	// "1234432S"		-	L1 L2 R1 R2 R2 R1 L2 SQUARE
+	else if ( !_CHEATCMP("S2344321") )
+		CloudyWeatherCheat();
+	
+	// "1234432C"		-	L1 L2 R1 R2 R2 R1 L2 CIRCLE
+	else if ( !_CHEATCMP("C2344321") )
+		RainyWeatherCheat();
+	
+	// "1234432X"		-	L1 L2 R1 R2 R2 R1 L2 CROSS
+	else if ( !_CHEATCMP("X2344321") )
+		FoggyWeatherCheat();
+	
+	// "CCCCCC321TCT"	-	CIRCLE CIRCLE CIRCLE CIRCLE CIRCLE CIRCLE R1 L2 L1 TRIANGLE CIRCLE TRIANGLE
+	else if ( !_CHEATCMP("TCT123CCCCCC") )
+		TankCheat();
+	
+	// "CCCSSSSS1TCT"	-	CIRCLE CIRCLE CIRCLE SQUARE SQUARE SQUARE SQUARE SQUARE L1 TRIANGLE CIRCLE TRIANGLE
+	else if ( !_CHEATCMP("TCT1SSSSSCCC") )
+		FastWeatherCheat();
+	
+	// "241324TSCT21"	-	L2 R2 L1 R1 L2 R2 TRIANGLE SQUARE CIRCLE TRIANGLE L2 L1
+	else if ( !_CHEATCMP("12TCST423142") )
+		BlowUpCarsCheat();
+	
+	// "RDLU12ULDR"		-	RIGHT DOWN LEFT UP L1 L2 UP LEFT DOWN RIGHT
+	else if ( !_CHEATCMP("RDLU21ULDR") )
+		ChangePlayerCheat();
+	
+	// "DULUX3421"		-	DOWN UP LEFT UP CROSS R1 R2 L2 L1
+	else if ( !_CHEATCMP("1243XULUD") )
+		MayhemCheat();
+	
+	// "DULUX3412"		-	DOWN UP LEFT UP CROSS R1 R2 L1 L2
+	else if ( !_CHEATCMP("2143XULUD") )
+		EverybodyAttacksPlayerCheat();
+	
+	// "43TX21UD"		-	R2 R1 TRIANGLE CROSS L2 L1 UP DOWN
+	else if ( !_CHEATCMP("DU12XT34") )
+		WeaponsForAllCheat();
+	
+	// "TURDS12"		-	TRIANGLE UP RIGHT DOWN SQUARE L1 L2
+	else if ( !_CHEATCMP("21SDRUT") )
+		FastTimeCheat();
+	
+	// "TURDS34"		-	TRIANGLE UP RIGHT DOWN SQUARE R1 R2
+	else if ( !_CHEATCMP("43SDRUT") )
+		SlowTimeCheat();
+
+	// "11S4T1T"		-	L1 L1 SQUARE R2 TRIANGLE L1 TRIANGLE
+	else if ( !_CHEATCMP("T1T4S11") )
+		OnlyRenderWheelsCheat();
+	
+	// "R4C32D13"		-	RIGHT R2 CIRCLE R1 L2 DOWN L1 R1
+	else if ( !_CHEATCMP("31D23C4R") )
+		ChittyChittyBangBangCheat();
+	
+	// "3141L33T"		-	R1 L1 R2 L1 LEFT R1 R1 TRIANGLE
+	else if ( !_CHEATCMP("T33L1413") )
+		StrongGripCheat();
+	
+	// "S1CD13TR1X"		-	SQUARE L1 CIRCLE DOWN L1 R1 TRIANGLE RIGHT L1 CROSS
+	else if ( !_CHEATCMP("X1RT31DC1S") )
+		NastyLimbsCheat();
+#undef _CHEATCMP
+}
+#endif
+
 void CPad::AddToPCCheatString(char c)
 {
 	for ( int32 i = ARRAY_SIZE(KeyBoardCheatString) - 2; i >= 0; i-- )
@@ -657,16 +969,21 @@ void CPad::Update(int16 unk)
 {
 	OldState = NewState;
 	
-	NewState = ReconcileTwoControllersInput(PCTempKeyState,   PCTempJoyState);
-	NewState = ReconcileTwoControllersInput(PCTempMouseState, NewState);
-	
+#if (defined GTA_PS2 || defined FIX_BUGS)
+	if (!CRecordDataForGame::IsPlayingBack() && !CRecordDataForChase::ShouldThisPadBeLeftAlone(unk))
+#endif
+	{
+		NewState = ReconcileTwoControllersInput(PCTempKeyState, PCTempJoyState);
+		NewState = ReconcileTwoControllersInput(PCTempMouseState, NewState);
+	}
+
 	PCTempJoyState.Clear();
 	PCTempKeyState.Clear();
 	PCTempMouseState.Clear();
 	
 	ProcessPCSpecificStuff();
 	
-	if ( ++iCurrHornHistory >= _TODOCONST(5) )
+	if ( ++iCurrHornHistory >= HORNHISTORY_SIZE )
 		iCurrHornHistory = 0;
 
 	bHornHistory[iCurrHornHistory] = GetHorn();
@@ -683,7 +1000,7 @@ void CPad::DoCheats(void)
 
 void CPad::DoCheats(int16 unk)
 {
-#ifdef PS2
+#ifdef GTA_PS2_STUFF
 	if ( GetTriangleJustDown() )
 		AddToCheatString('T');
 	
@@ -2086,7 +2403,31 @@ int32 *CPad::EditCodesForControls(int32 *pRsKeys, int32 nSize)
 	return pRsKeys;
 }
 
-STARTPATCHES	
+STARTPATCHES
+	InjectHook(0x490D90, &WeaponCheat, PATCH_JUMP);
+	InjectHook(0x490E70, &HealthCheat, PATCH_JUMP);
+	InjectHook(0x490EE0, &TankCheat, PATCH_JUMP);
+	InjectHook(0x491040, &BlowUpCarsCheat, PATCH_JUMP);
+	InjectHook(0x4910B0, &ChangePlayerCheat, PATCH_JUMP);
+	InjectHook(0x4911C0, &MayhemCheat, PATCH_JUMP);
+	InjectHook(0x491270, &EverybodyAttacksPlayerCheat, PATCH_JUMP);
+	InjectHook(0x491370, &WeaponsForAllCheat, PATCH_JUMP);
+	InjectHook(0x4913A0, &FastTimeCheat, PATCH_JUMP);
+	InjectHook(0x4913F0, &SlowTimeCheat, PATCH_JUMP);
+	InjectHook(0x491430, &MoneyCheat, PATCH_JUMP);
+	InjectHook(0x491460, &ArmourCheat, PATCH_JUMP);
+	InjectHook(0x491490, &WantedLevelUpCheat, PATCH_JUMP);
+	InjectHook(0x4914F0, &WantedLevelDownCheat, PATCH_JUMP);
+	InjectHook(0x491520, &SunnyWeatherCheat, PATCH_JUMP);
+	InjectHook(0x491550, &CloudyWeatherCheat, PATCH_JUMP);
+	InjectHook(0x491580, &RainyWeatherCheat, PATCH_JUMP);
+	InjectHook(0x4915B0, &FoggyWeatherCheat, PATCH_JUMP);
+	InjectHook(0x4915E0, &FastWeatherCheat, PATCH_JUMP);
+	InjectHook(0x491610, &OnlyRenderWheelsCheat, PATCH_JUMP);
+	InjectHook(0x491640, &ChittyChittyBangBangCheat, PATCH_JUMP);
+	InjectHook(0x491670, &StrongGripCheat, PATCH_JUMP);
+	InjectHook(0x4916A0, &NastyLimbsCheat, PATCH_JUMP);
+
 	InjectHook(0x4916C0, &CControllerState::Clear, PATCH_JUMP);
 	InjectHook(0x491760, &CKeyboardState::Clear, PATCH_JUMP);
 	InjectHook(0x491A10, &CPad::Clear, PATCH_JUMP);
diff --git a/src/core/Pad.h b/src/core/Pad.h
index ca44a9f7..cb705c6b 100644
--- a/src/core/Pad.h
+++ b/src/core/Pad.h
@@ -136,6 +136,10 @@ enum
 class CPad
 {
 public:
+	enum
+	{
+		HORNHISTORY_SIZE = 5,
+	};
 	CControllerState NewState;
 	CControllerState OldState;
 	CControllerState PCTempKeyState;
@@ -146,11 +150,11 @@ public:
 	int16 Mode;
 	int16 ShakeDur;
 	uint8 ShakeFreq;
-	bool bHornHistory[5];
+	bool bHornHistory[HORNHISTORY_SIZE];
 	uint8 iCurrHornHistory;
 	uint8 DisablePlayerControls;
 	int8 bApplyBrakes;
-	char _unk[12]; //int32 unk[3];
+	char CheatString[12];
 	char _pad0[3];
 	int32 LastTimeTouched;
 	int32 AverageWeapon;
@@ -161,6 +165,7 @@ public:
 
 	static bool &bDisplayNoControllerMessage;
 	static bool &bObsoleteControllerMessage;
+	static bool bOldDisplayNoControllerMessage;
 	static bool &m_bMapPadOneToPadTwo;
 	
 	static CKeyboardState &OldKeyState;
@@ -172,8 +177,9 @@ public:
 	static CMouseControllerState &PCTempMouseControllerState;
 	
 	
-	
-	
+#ifdef GTA_PS2_STUFF
+	static void Initialise(void);
+#endif
 	void Clear(bool bResetPlayerControls);
 	void ClearMouseHistory();
 	void UpdateMouse();
@@ -181,6 +187,9 @@ public:
 	void StartShake(int16 nDur, uint8 nFreq);
 	void StartShake_Distance(int16 nDur, uint8 nFreq, float fX, float fY, float fz);
 	void StartShake_Train(float fX, float fY);
+#ifdef GTA_PS2_STUFF
+	void AddToCheatString(char c);
+#endif
 	void AddToPCCheatString(char c);
 
 	static void UpdatePads(void);
@@ -409,6 +418,7 @@ public:
 	bool GetLeftStickXJustDown() { return !!(NewState.LeftStickX && !OldState.LeftStickX); }
 	bool GetLeftStickYJustDown() { return !!(NewState.LeftStickY && !OldState.LeftStickY); }
   
+	bool GetTriangleJustUp() { return !!(!NewState.Triangle && OldState.Triangle); }
 	bool GetCrossJustUp() { return !!(!NewState.Cross && OldState.Cross); }
 	bool GetSquareJustUp() { return !!(!NewState.Square && OldState.Square); }
 	bool GetDPadUpJustUp() { return !!(!NewState.DPadUp && OldState.DPadUp); }
diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp
index ead32ee7..0043c2f4 100644
--- a/src/core/PlayerInfo.cpp
+++ b/src/core/PlayerInfo.cpp
@@ -48,45 +48,45 @@ CPlayerInfo::GetPos()
 
 void
 CPlayerInfo::LoadPlayerSkin()
-{
-	DeletePlayerSkin();
-
-	m_pSkinTexture = CPlayerSkin::GetSkinTexture(m_aSkinName);
-	if (!m_pSkinTexture)
+{
+	DeletePlayerSkin();
+
+	m_pSkinTexture = CPlayerSkin::GetSkinTexture(m_aSkinName);
+	if (!m_pSkinTexture)
 		m_pSkinTexture = CPlayerSkin::GetSkinTexture(DEFAULT_SKIN_NAME);
 }
 
 void
 CPlayerInfo::DeletePlayerSkin()
-{
-	if (m_pSkinTexture) {
-		RwTextureDestroy(m_pSkinTexture);
-		m_pSkinTexture = nil;
+{
+	if (m_pSkinTexture) {
+		RwTextureDestroy(m_pSkinTexture);
+		m_pSkinTexture = nil;
 	}
 }
 
-void
-CPlayerInfo::KillPlayer()
-{
-	if (m_WBState != WBSTATE_PLAYING) return;
-
-	m_WBState = WBSTATE_WASTED;
-	m_nWBTime = CTimer::GetTimeInMilliseconds();
-	CDarkel::ResetOnPlayerDeath();
-	CMessages::AddBigMessage(TheText.Get("DEAD"), 4000, 2);
-	CStats::TimesDied++;
+void
+CPlayerInfo::KillPlayer()
+{
+	if (m_WBState != WBSTATE_PLAYING) return;
+
+	m_WBState = WBSTATE_WASTED;
+	m_nWBTime = CTimer::GetTimeInMilliseconds();
+	CDarkel::ResetOnPlayerDeath();
+	CMessages::AddBigMessage(TheText.Get("DEAD"), 4000, 2);
+	CStats::TimesDied++;
 }
 
-void
-CPlayerInfo::ArrestPlayer()
-{
-	if (m_WBState != WBSTATE_PLAYING) return;
-
-	m_WBState = WBSTATE_BUSTED;
-	m_nWBTime = CTimer::GetTimeInMilliseconds();
-	CDarkel::ResetOnPlayerDeath();
-	CMessages::AddBigMessage(TheText.Get("BUSTED"), 5000, 2);
-	CStats::TimesArrested++;
+void
+CPlayerInfo::ArrestPlayer()
+{
+	if (m_WBState != WBSTATE_PLAYING) return;
+
+	m_WBState = WBSTATE_BUSTED;
+	m_nWBTime = CTimer::GetTimeInMilliseconds();
+	CDarkel::ResetOnPlayerDeath();
+	CMessages::AddBigMessage(TheText.Get("BUSTED"), 5000, 2);
+	CStats::TimesArrested++;
 }
 
 bool
@@ -105,102 +105,102 @@ CPlayerInfo::PlayerFailedCriticalMission()
 	CDarkel::ResetOnPlayerDeath();
 }
 
-void
-CPlayerInfo::Clear(void)
-{
-	m_pPed = nil;
-	m_pRemoteVehicle = nil;
-	if (m_pVehicleEx) {
-		m_pVehicleEx->bUsingSpecialColModel = false;
-		m_pVehicleEx = nil;
-	}
-	m_nVisibleMoney = 0;
-	m_nMoney = m_nVisibleMoney;
-	m_WBState = WBSTATE_PLAYING;
-	m_nWBTime = 0;
-	m_nTrafficMultiplier = 0;
-	m_fRoadDensity = 1.0f;
-	m_bInRemoteMode = false;
-	m_bUnusedTaxiThing = false;
-	m_nUnusedTaxiTimer = 0;
-	m_nCollectedPackages = 0;
-	m_nTotalPackages = 3;
-	m_nTimeLastHealthLoss = 0;
-	m_nTimeLastArmourLoss = 0;
-	m_nNextSexFrequencyUpdateTime = 0;
-	m_nNextSexMoneyUpdateTime = 0;
-	m_nSexFrequency = 0;
-	m_pHooker = nil;
-	m_nTimeTankShotGun = 0;
-	field_248 = 0;
-	m_nUpsideDownCounter = 0;
-	m_bInfiniteSprint = false;
-	m_bFastReload = false;
-	m_bGetOutOfJailFree = false;
-	m_bGetOutOfHospitalFree = false;
-	m_nPreviousTimeRewardedForExplosion = 0;
-	m_nExplosionsSinceLastReward = 0;
+void
+CPlayerInfo::Clear(void)
+{
+	m_pPed = nil;
+	m_pRemoteVehicle = nil;
+	if (m_pVehicleEx) {
+		m_pVehicleEx->bUsingSpecialColModel = false;
+		m_pVehicleEx = nil;
+	}
+	m_nVisibleMoney = 0;
+	m_nMoney = m_nVisibleMoney;
+	m_WBState = WBSTATE_PLAYING;
+	m_nWBTime = 0;
+	m_nTrafficMultiplier = 0;
+	m_fRoadDensity = 1.0f;
+	m_bInRemoteMode = false;
+	m_bUnusedTaxiThing = false;
+	m_nUnusedTaxiTimer = 0;
+	m_nCollectedPackages = 0;
+	m_nTotalPackages = 3;
+	m_nTimeLastHealthLoss = 0;
+	m_nTimeLastArmourLoss = 0;
+	m_nNextSexFrequencyUpdateTime = 0;
+	m_nNextSexMoneyUpdateTime = 0;
+	m_nSexFrequency = 0;
+	m_pHooker = nil;
+	m_nTimeTankShotGun = 0;
+	field_248 = 0;
+	m_nUpsideDownCounter = 0;
+	m_bInfiniteSprint = false;
+	m_bFastReload = false;
+	m_bGetOutOfJailFree = false;
+	m_bGetOutOfHospitalFree = false;
+	m_nPreviousTimeRewardedForExplosion = 0;
+	m_nExplosionsSinceLastReward = 0;
 }
 
-void
-CPlayerInfo::BlowUpRCBuggy(void)
-{
-	if (!m_pRemoteVehicle || m_pRemoteVehicle->bRemoveFromWorld)
-		return;
-
-	CRemote::TakeRemoteControlledCarFromPlayer();
-	m_pRemoteVehicle->BlowUpCar(FindPlayerPed());
-}
-
-void
-CPlayerInfo::CancelPlayerEnteringCars(CVehicle *car)
-{
-	if (!car || car == m_pPed->m_pMyVehicle) {
-		if (m_pPed->EnteringCar())
-			m_pPed->QuitEnteringCar();
-	}
-	if (m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)
-		m_pPed->ClearObjective();
+void
+CPlayerInfo::BlowUpRCBuggy(void)
+{
+	if (!m_pRemoteVehicle || m_pRemoteVehicle->bRemoveFromWorld)
+		return;
+
+	CRemote::TakeRemoteControlledCarFromPlayer();
+	m_pRemoteVehicle->BlowUpCar(FindPlayerPed());
 }
 
-void
-CPlayerInfo::MakePlayerSafe(bool toggle)
-{
-	if (toggle) {
-		CTheScripts::ResetCountdownToMakePlayerUnsafe();
-		m_pPed->m_pWanted->m_bIgnoredByEveryone = true;
-		CWorld::StopAllLawEnforcersInTheirTracks();
-		CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_20;
-		CPad::StopPadsShaking();
-		m_pPed->bBulletProof = true;
-		m_pPed->bFireProof = true;
-		m_pPed->bCollisionProof = true;
-		m_pPed->bMeleeProof = true;
-		m_pPed->bOnlyDamagedByPlayer = true;
-		m_pPed->bExplosionProof = true;
-		m_pPed->m_bCanBeDamaged = false;
-		((CPlayerPed*)m_pPed)->ClearAdrenaline();
-		CancelPlayerEnteringCars(false);
-		gFireManager.ExtinguishPoint(GetPos(), 4000.0f);
-		CExplosion::RemoveAllExplosionsInArea(GetPos(), 4000.0f);
-		CProjectileInfo::RemoveAllProjectiles();
-		CWorld::SetAllCarsCanBeDamaged(false);
-		CWorld::ExtinguishAllCarFiresInArea(GetPos(), 4000.0f);
-		CReplay::DisableReplays();
-
-	} else if (!CGame::playingIntro && !CTheScripts::IsCountdownToMakePlayerUnsafeOn()) {
-		m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
-		CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_20;
-		m_pPed->bBulletProof = false;
-		m_pPed->bFireProof = false;
-		m_pPed->bCollisionProof = false;
-		m_pPed->bMeleeProof = false;
-		m_pPed->bOnlyDamagedByPlayer = false;
-		m_pPed->bExplosionProof = false;
-		m_pPed->m_bCanBeDamaged = true;
-		CWorld::SetAllCarsCanBeDamaged(true);
-		CReplay::EnableReplays();
-	}
+void
+CPlayerInfo::CancelPlayerEnteringCars(CVehicle *car)
+{
+	if (!car || car == m_pPed->m_pMyVehicle) {
+		if (m_pPed->EnteringCar())
+			m_pPed->QuitEnteringCar();
+	}
+	if (m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)
+		m_pPed->ClearObjective();
+}
+
+void
+CPlayerInfo::MakePlayerSafe(bool toggle)
+{
+	if (toggle) {
+		CTheScripts::ResetCountdownToMakePlayerUnsafe();
+		m_pPed->m_pWanted->m_bIgnoredByEveryone = true;
+		CWorld::StopAllLawEnforcersInTheirTracks();
+		CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_20;
+		CPad::StopPadsShaking();
+		m_pPed->bBulletProof = true;
+		m_pPed->bFireProof = true;
+		m_pPed->bCollisionProof = true;
+		m_pPed->bMeleeProof = true;
+		m_pPed->bOnlyDamagedByPlayer = true;
+		m_pPed->bExplosionProof = true;
+		m_pPed->m_bCanBeDamaged = false;
+		((CPlayerPed*)m_pPed)->ClearAdrenaline();
+		CancelPlayerEnteringCars(false);
+		gFireManager.ExtinguishPoint(GetPos(), 4000.0f);
+		CExplosion::RemoveAllExplosionsInArea(GetPos(), 4000.0f);
+		CProjectileInfo::RemoveAllProjectiles();
+		CWorld::SetAllCarsCanBeDamaged(false);
+		CWorld::ExtinguishAllCarFiresInArea(GetPos(), 4000.0f);
+		CReplay::DisableReplays();
+
+	} else if (!CGame::playingIntro && !CTheScripts::IsCountdownToMakePlayerUnsafeOn()) {
+		m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
+		CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_20;
+		m_pPed->bBulletProof = false;
+		m_pPed->bFireProof = false;
+		m_pPed->bCollisionProof = false;
+		m_pPed->bMeleeProof = false;
+		m_pPed->bOnlyDamagedByPlayer = false;
+		m_pPed->bExplosionProof = false;
+		m_pPed->m_bCanBeDamaged = true;
+		CWorld::SetAllCarsCanBeDamaged(true);
+		CReplay::EnableReplays();
+	}
 }
 
 bool
@@ -216,347 +216,347 @@ CPlayerInfo::IsRestartingAfterArrest()
 }
 
 // lastCloseness is passed to other calls of this function
-void
-CPlayerInfo::EvaluateCarPosition(CEntity *carToTest, CPed *player, float carBoundCentrePedDist, float *lastCloseness, CVehicle **closestCarOutput)
-{
-	// This dist used for determining the angle to face
-	CVector2D dist(carToTest->GetPosition() - player->GetPosition());
-	float neededTurn = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y) - CGeneral::GetATanOfXY(dist.x, dist.y);
-	while (neededTurn >= PI) {
-		neededTurn -= 2 * PI;
-	}
-
-	while (neededTurn < -PI) {
-		neededTurn += 2 * PI;
-	}
-
-	// This dist used for evaluating cars' distances, weird...
-	// Accounts inverted needed turn (or needed turn in long way) and car dist.
-	float closeness = (1.0f - Abs(neededTurn) / TWOPI) * (10.0f - carBoundCentrePedDist);
-	if (closeness > *lastCloseness) {
-		*lastCloseness = closeness;
-		*closestCarOutput = (CVehicle*)carToTest;
-	}
+void
+CPlayerInfo::EvaluateCarPosition(CEntity *carToTest, CPed *player, float carBoundCentrePedDist, float *lastCloseness, CVehicle **closestCarOutput)
+{
+	// This dist used for determining the angle to face
+	CVector2D dist(carToTest->GetPosition() - player->GetPosition());
+	float neededTurn = CGeneral::GetATanOfXY(player->GetForward().x, player->GetForward().y) - CGeneral::GetATanOfXY(dist.x, dist.y);
+	while (neededTurn >= PI) {
+		neededTurn -= 2 * PI;
+	}
+
+	while (neededTurn < -PI) {
+		neededTurn += 2 * PI;
+	}
+
+	// This dist used for evaluating cars' distances, weird...
+	// Accounts inverted needed turn (or needed turn in long way) and car dist.
+	float closeness = (1.0f - Abs(neededTurn) / TWOPI) * (10.0f - carBoundCentrePedDist);
+	if (closeness > *lastCloseness) {
+		*lastCloseness = closeness;
+		*closestCarOutput = (CVehicle*)carToTest;
+	}
 }
 
 // There is something unfinished in here... Sadly all IDBs we have have it unfinished.
-void
-CPlayerInfo::AwardMoneyForExplosion(CVehicle *wreckedCar)
-{
-	if (CTimer::GetTimeInMilliseconds() - m_nPreviousTimeRewardedForExplosion < 6000)
-		++m_nExplosionsSinceLastReward;
-	else
-		m_nExplosionsSinceLastReward = 1;
-
-	m_nPreviousTimeRewardedForExplosion = CTimer::GetTimeInMilliseconds();
-	int award = wreckedCar->pHandling->nMonetaryValue * 0.002f;
-	sprintf(gString, "$%d", award);
-#ifdef MONEY_MESSAGES
-	// This line is a leftover from PS2, I don't know what it was meant to be.
-	// CVector sth(TheCamera.GetPosition() * 4.0f);
-
-	CMoneyMessages::RegisterOne(wreckedCar->GetPosition() + CVector(0.0f, 0.0f, 2.0f), gString, 0, 255, 0, 2.0f, 0.5f);
-#endif
-	CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
-
-	for (int i = m_nExplosionsSinceLastReward; i > 1; --i) {
-		CGeneral::GetRandomNumber();
-		CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
-	}
+void
+CPlayerInfo::AwardMoneyForExplosion(CVehicle *wreckedCar)
+{
+	if (CTimer::GetTimeInMilliseconds() - m_nPreviousTimeRewardedForExplosion < 6000)
+		++m_nExplosionsSinceLastReward;
+	else
+		m_nExplosionsSinceLastReward = 1;
+
+	m_nPreviousTimeRewardedForExplosion = CTimer::GetTimeInMilliseconds();
+	int award = wreckedCar->pHandling->nMonetaryValue * 0.002f;
+	sprintf(gString, "$%d", award);
+#ifdef MONEY_MESSAGES
+	// This line is a leftover from PS2, I don't know what it was meant to be.
+	// CVector sth(TheCamera.GetPosition() * 4.0f);
+
+	CMoneyMessages::RegisterOne(wreckedCar->GetPosition() + CVector(0.0f, 0.0f, 2.0f), gString, 0, 255, 0, 2.0f, 0.5f);
+#endif
+	CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
+
+	for (int i = m_nExplosionsSinceLastReward; i > 1; --i) {
+		CGeneral::GetRandomNumber();
+		CWorld::Players[CWorld::PlayerInFocus].m_nMoney += award;
+	}
 }
 
-void
-CPlayerInfo::SavePlayerInfo(uint8 *buf, uint32 *size)
-{
-	// Interesting
-	*size = sizeof(CPlayerInfo);
-
-INITSAVEBUF
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nMoney);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_WBState);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nWBTime);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bFastReload);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree);
-	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree);
-	for (int i = 0; i < sizeof(CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName); i++) {
-		WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName[i]);
-	}
-// Save struct is different
-// VALIDATESAVEBUF(*size)
+void
+CPlayerInfo::SavePlayerInfo(uint8 *buf, uint32 *size)
+{
+	// Interesting
+	*size = sizeof(CPlayerInfo);
+
+INITSAVEBUF
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nMoney);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_WBState);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nWBTime);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bFastReload);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree);
+	WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree);
+	for (int i = 0; i < sizeof(CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName); i++) {
+		WriteSaveBuf(buf, CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName[i]);
+	}
+// Save struct is different
+// VALIDATESAVEBUF(*size)
 }
 
-void
-CPlayerInfo::LoadPlayerInfo(uint8 *buf, uint32 size)
-{
-INITSAVEBUF
-	CWorld::Players[CWorld::PlayerInFocus].m_nMoney = ReadSaveBuf<uint32>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_WBState = ReadSaveBuf<int8>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_nWBTime = ReadSaveBuf<uint32>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier = ReadSaveBuf<int16>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity = ReadSaveBuf<float>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney = ReadSaveBuf<int32>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages = ReadSaveBuf<int32>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages = ReadSaveBuf<int32>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint = ReadSaveBuf<bool>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_bFastReload = ReadSaveBuf<bool>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree = ReadSaveBuf<bool>(buf);
-	CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree = ReadSaveBuf<bool>(buf);
-	for (int i = 0; i < sizeof(CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName); i++) {
-		CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName[i] = ReadSaveBuf<char>(buf);
-	}
-// Save struct is different
-// VALIDATESAVEBUF(size)
+void
+CPlayerInfo::LoadPlayerInfo(uint8 *buf, uint32 size)
+{
+INITSAVEBUF
+	CWorld::Players[CWorld::PlayerInFocus].m_nMoney = ReadSaveBuf<uint32>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_WBState = ReadSaveBuf<int8>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_nWBTime = ReadSaveBuf<uint32>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_nTrafficMultiplier = ReadSaveBuf<int16>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_fRoadDensity = ReadSaveBuf<float>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney = ReadSaveBuf<int32>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages = ReadSaveBuf<int32>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages = ReadSaveBuf<int32>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint = ReadSaveBuf<bool>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_bFastReload = ReadSaveBuf<bool>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfJailFree = ReadSaveBuf<bool>(buf);
+	CWorld::Players[CWorld::PlayerInFocus].m_bGetOutOfHospitalFree = ReadSaveBuf<bool>(buf);
+	for (int i = 0; i < sizeof(CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName); i++) {
+		CWorld::Players[CWorld::PlayerInFocus].m_aPlayerName[i] = ReadSaveBuf<char>(buf);
+	}
+// Save struct is different
+// VALIDATESAVEBUF(size)
 }
 
-void
-CPlayerInfo::FindClosestCarSectorList(CPtrList& carList, CPed* ped, float unk1, float unk2, float unk3, float unk4, float* lastCloseness, CVehicle** closestCarOutput)
-{
-	for (CPtrNode* node = carList.first; node; node = node->next) {
-		CVehicle *car = (CVehicle*)node->item;
-		if(car->m_scanCode != CWorld::GetCurrentScanCode()) {
-			if (!car->bUsesCollision || !car->IsVehicle())
-				continue;
-
-			car->m_scanCode = CWorld::GetCurrentScanCode();
-			if (car->m_status != STATUS_WRECKED && car->m_status != STATUS_TRAIN_MOVING
-				&& (car->GetUp().z > 0.3f || (car->IsVehicle() && ((CVehicle*)car)->m_vehType == VEHICLE_TYPE_BIKE))) {
-				CVector carCentre = car->GetBoundCentre();
-
-				if (Abs(ped->GetPosition().z - carCentre.z) < 2.0f) {
-					float dist = (ped->GetPosition() - carCentre).Magnitude2D();
-					if (dist <= 10.0f && !CCranes::IsThisCarBeingCarriedByAnyCrane(car)) {
-						EvaluateCarPosition(car, ped, dist, lastCloseness, closestCarOutput);
-					}
-				}
-			}
-		}
-	}
+void
+CPlayerInfo::FindClosestCarSectorList(CPtrList& carList, CPed* ped, float unk1, float unk2, float unk3, float unk4, float* lastCloseness, CVehicle** closestCarOutput)
+{
+	for (CPtrNode* node = carList.first; node; node = node->next) {
+		CVehicle *car = (CVehicle*)node->item;
+		if(car->m_scanCode != CWorld::GetCurrentScanCode()) {
+			if (!car->bUsesCollision || !car->IsVehicle())
+				continue;
+
+			car->m_scanCode = CWorld::GetCurrentScanCode();
+			if (car->m_status != STATUS_WRECKED && car->m_status != STATUS_TRAIN_MOVING
+				&& (car->GetUp().z > 0.3f || (car->IsVehicle() && ((CVehicle*)car)->m_vehType == VEHICLE_TYPE_BIKE))) {
+				CVector carCentre = car->GetBoundCentre();
+
+				if (Abs(ped->GetPosition().z - carCentre.z) < 2.0f) {
+					float dist = (ped->GetPosition() - carCentre).Magnitude2D();
+					if (dist <= 10.0f && !CCranes::IsThisCarBeingCarriedByAnyCrane(car)) {
+						EvaluateCarPosition(car, ped, dist, lastCloseness, closestCarOutput);
+					}
+				}
+			}
+		}
+	}
 }
 
-void
-CPlayerInfo::Process(void)
-{
-	// Unused taxi feature. Gives you a dollar for every second with a passenger. Can be toggled via 0x29A opcode.
-	bool startTaxiTimer = true;
-	if (m_bUnusedTaxiThing && m_pPed->bInVehicle) {
-		CVehicle *veh = m_pPed->m_pMyVehicle;
-		if ((veh->m_modelIndex == MI_TAXI || veh->m_modelIndex == MI_CABBIE || veh->m_modelIndex == MI_BORGNINE)
-			&& veh->pDriver == m_pPed && veh->m_nNumPassengers != 0) {
-			for (uint32 timePassed = CTimer::GetTimeInMilliseconds() - m_nUnusedTaxiTimer; timePassed >= 1000; m_nUnusedTaxiTimer += 1000) {
-				timePassed -= 1000;
-				++m_nMoney;
-			}
-			startTaxiTimer = false;
-		}
-	}
-	if (startTaxiTimer)
-		m_nUnusedTaxiTimer = CTimer::GetTimeInMilliseconds();
-
-	// The effect that makes money counter does while earning/losing money
-	if (m_nVisibleMoney != m_nMoney) {
-		int diff = m_nMoney - m_nVisibleMoney;
-		int diffAbs = Abs(diff);
-		int changeBy;
-
-		if (diffAbs > 100000)
-			changeBy = 12345;
-		else if (diffAbs > 10000)
-			changeBy = 1234;
-		else if (diffAbs > 1000)
-			changeBy = 123;
-		else if (diffAbs > 50)
-			changeBy = 42;
-		else
-			changeBy = 1;
-
-		if (diff < 0)
-			m_nVisibleMoney -= changeBy;
-		else
-			m_nVisibleMoney += changeBy;
-	}
-
-	if (!(CTimer::GetFrameCounter() & 15)) {
-		CVector2D playerPos = m_pPed->bInVehicle ? m_pPed->m_pMyVehicle->GetPosition() : m_pPed->GetPosition();
-		m_fRoadDensity = ThePaths.CalcRoadDensity(playerPos.x, playerPos.y);
-	}
-
-	m_fRoadDensity = clamp(m_fRoadDensity, 0.4f, 1.45f);
-
-	// Because vehicle enter/exit use same key binding.
-	bool enterOrExitVeh;
-	if (m_pPed->bVehExitWillBeInstant && m_pPed->bInVehicle)
-		enterOrExitVeh = CPad::GetPad(0)->ExitVehicleJustDown();
-	else
-		enterOrExitVeh = CPad::GetPad(0)->GetExitVehicle();
-
-	if (enterOrExitVeh && m_pPed->m_nPedState != PED_SNIPER_MODE && m_pPed->m_nPedState != PED_ROCKET_ODE) {
-		if (m_pPed->bInVehicle) {
-			if (!m_pRemoteVehicle) {
-				CEntity *surfaceBelowVeh = m_pPed->m_pMyVehicle->m_pCurGroundEntity;
-				if (!surfaceBelowVeh || !CBridge::ThisIsABridgeObjectMovingUp(surfaceBelowVeh->m_modelIndex)) {
-					CVehicle *veh = m_pPed->m_pMyVehicle;
-					if (!veh->IsBoat() || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
-
-						// This condition will always return true, else block was probably WIP Miami code.
-						if (veh->m_vehType != VEHICLE_TYPE_BIKE || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
-							if (veh->m_status != STATUS_WRECKED && veh->m_status != STATUS_TRAIN_MOVING && veh->m_nDoorLock != CARLOCK_LOCKED_PLAYER_INSIDE) {
-								if (veh->m_vecMoveSpeed.Magnitude() < 0.17f && CTimer::GetTimeScale() >= 0.5f && !veh->bIsInWater) {
-									m_pPed->SetObjective(OBJECTIVE_LEAVE_VEHICLE, veh);
-								}
-							}
-						} else {
-							CVector sth = 0.7f * veh->GetRight() + veh->GetPosition();
-							bool found = false;
-							float groundZ = CWorld::FindGroundZFor3DCoord(sth.x, sth.y, 2.0f + sth.z, &found);
-
-							if (found)
-								sth.z = 1.0f + groundZ;
-							m_pPed->m_nPedState = PED_IDLE;
-							m_pPed->SetMoveState(PEDMOVE_STILL);
-							CPed::PedSetOutCarCB(0, m_pPed);
-							CAnimManager::BlendAnimation(m_pPed->GetClump(), m_pPed->m_animGroup, ANIM_IDLE_STANCE, 100.0f);
-							CAnimManager::BlendAnimation(m_pPed->GetClump(), ASSOCGRP_STD, ANIM_FALL_LAND, 100.0f);
-							m_pPed->GetPosition() = sth;
-							m_pPed->SetMoveState(PEDMOVE_STILL);
-							m_pPed->m_vecMoveSpeed = veh->m_vecMoveSpeed;
-						}
-					} else {
-						// The code in here was under CPed::SetExitBoat in VC, did the same for here.
-						m_pPed->SetExitBoat(veh);
-						m_pPed->bTryingToReachDryLand = true;
-					}
-				}
-			}
-		} else {
-			// Enter vehicle
-			if (CPad::GetPad(0)->ExitVehicleJustDown()) {
-				bool weAreOnBoat = false;
-				float lastCloseness = 0.0f;
-				CVehicle *carBelow = nil;
-				CEntity *surfaceBelow = m_pPed->m_pCurrentPhysSurface;
-				if (surfaceBelow && surfaceBelow->IsVehicle()) {
-					carBelow = (CVehicle*)surfaceBelow;
-					if (carBelow->IsBoat()) {
-						weAreOnBoat = true;
-						m_pPed->bOnBoat = true;
-#ifdef VC_PED_PORTS
-						if (carBelow->m_status != STATUS_WRECKED && carBelow->GetUp().z > 0.3f)
-#else
-						if (carBelow->m_status != STATUS_WRECKED)
-#endif
-							m_pPed->SetSeekBoatPosition(carBelow);
-					}
-				}
-				// Find closest car
-				if (!weAreOnBoat) {
-					float minX = m_pPed->GetPosition().x - 10.0f;
-					float maxX = 10.0f + m_pPed->GetPosition().x;
-					float minY = m_pPed->GetPosition().y - 10.0f;
-					float maxY = 10.0f + m_pPed->GetPosition().y;
-
-					int minXSector = CWorld::GetSectorIndexX(minX);
-					if (minXSector < 0) minXSector = 0;
-					int minYSector = CWorld::GetSectorIndexY(minY);
-					if (minYSector < 0) minYSector = 0;
-					int maxXSector = CWorld::GetSectorIndexX(maxX);
-					if (maxXSector > NUMSECTORS_X - 1) maxXSector = NUMSECTORS_X - 1;
-					int maxYSector = CWorld::GetSectorIndexY(maxY);
-					if (maxYSector > NUMSECTORS_Y - 1) maxYSector = NUMSECTORS_Y - 1;
-
-					CWorld::AdvanceCurrentScanCode();
-
-					for (int curY = minYSector; curY <= maxYSector; curY++) {
-						for (int curX = minXSector; curX <= maxXSector; curX++) {
-							CSector *sector = CWorld::GetSector(curX, curY);
-							FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES], m_pPed,
-								minX, minY, maxX, maxY, &lastCloseness, &carBelow);
-							FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], m_pPed,
-								minX, minY, maxX, maxY, &lastCloseness, &carBelow);
-						}
-					}
-				}
-				// carBelow is now closest vehicle
-				if (carBelow && !weAreOnBoat) {
-					if (carBelow->m_status == STATUS_TRAIN_NOT_MOVING) {
-						m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, carBelow);
-					} else if (carBelow->IsBoat()) {
-						if (!carBelow->pDriver) {
-							m_pPed->m_vehEnterType = 0;
-							m_pPed->SetEnterCar(carBelow, m_pPed->m_vehEnterType);
-						}
-					} else {
-						m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carBelow);
-					}
-				}
-			}
-		}
-	}
-	if (m_bInRemoteMode) {
-		uint32 timeWithoutRemoteCar = CTimer::GetTimeInMilliseconds() - m_nTimeLostRemoteCar;
-		if (CTimer::GetPreviousTimeInMilliseconds() - m_nTimeLostRemoteCar < 1000 && timeWithoutRemoteCar >= 1000 && m_WBState == WBSTATE_PLAYING) {
-			TheCamera.SetFadeColour(0, 0, 0);
-			TheCamera.Fade(1.0f, 0);
-		}
-		if (timeWithoutRemoteCar > 2000) {
-			if (m_WBState == WBSTATE_PLAYING) {
-				TheCamera.RestoreWithJumpCut();
-				TheCamera.SetFadeColour(0, 0, 0);
-				TheCamera.Fade(1.0f, 1);
-				TheCamera.Process();
-				CTimer::Stop();
-				CCullZones::ForceCullZoneCoors(TheCamera.GetPosition());
-				CRenderer::RequestObjectsInFrustum();
-				CStreaming::LoadAllRequestedModels(false);
-				CTimer::Update();
-			}
-			m_bInRemoteMode = false;
-			CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle = nil;
-			if (FindPlayerVehicle()) {
-				FindPlayerVehicle()->m_status = STATUS_PLAYER;
-			}
-		}
-	}
-	if (!(CTimer::GetFrameCounter() & 31)) {
-		CVehicle *veh = FindPlayerVehicle();
-		if (veh && m_pPed->bInVehicle && veh->GetUp().z < 0.0f
-			&& veh->m_vecMoveSpeed.Magnitude() < 0.05f && veh->IsCar() && !veh->bIsInWater) {
-
-			if (veh->GetUp().z < -0.5f) {
-				m_nUpsideDownCounter += 2;
-			
-			} else {
-				m_nUpsideDownCounter++;
-			}
-		} else {
-			m_nUpsideDownCounter = 0;
-		}
-
-		if (m_nUpsideDownCounter > 6 && veh->bCanBeDamaged) {
-			veh->m_fHealth = 249.0f < veh->m_fHealth ? 249.0f : veh->m_fHealth;
-			if (veh->IsCar()) {
-				CAutomobile* car = (CAutomobile*)veh;
-				car->Damage.SetEngineStatus(225);
-				car->m_pSetOnFireEntity = nil;
-			}
-		}
-	}
-	if (FindPlayerVehicle()) {
-		CVehicle *veh = FindPlayerVehicle();
-		veh->m_nZoneLevel = -1;
-		for (int i = 0; i < ARRAY_SIZE(veh->pPassengers); i++) {
-			if (veh->pPassengers[i])
-				veh->pPassengers[i]->m_nZoneLevel = 0;
-		}
-		CStats::DistanceTravelledInVehicle += veh->m_fDistanceTravelled;
-	} else {
-		CStats::DistanceTravelledOnFoot += FindPlayerPed()->m_fDistanceTravelled;
-	}
+void
+CPlayerInfo::Process(void)
+{
+	// Unused taxi feature. Gives you a dollar for every second with a passenger. Can be toggled via 0x29A opcode.
+	bool startTaxiTimer = true;
+	if (m_bUnusedTaxiThing && m_pPed->bInVehicle) {
+		CVehicle *veh = m_pPed->m_pMyVehicle;
+		if ((veh->m_modelIndex == MI_TAXI || veh->m_modelIndex == MI_CABBIE || veh->m_modelIndex == MI_BORGNINE)
+			&& veh->pDriver == m_pPed && veh->m_nNumPassengers != 0) {
+			for (uint32 timePassed = CTimer::GetTimeInMilliseconds() - m_nUnusedTaxiTimer; timePassed >= 1000; m_nUnusedTaxiTimer += 1000) {
+				timePassed -= 1000;
+				++m_nMoney;
+			}
+			startTaxiTimer = false;
+		}
+	}
+	if (startTaxiTimer)
+		m_nUnusedTaxiTimer = CTimer::GetTimeInMilliseconds();
+
+	// The effect that makes money counter does while earning/losing money
+	if (m_nVisibleMoney != m_nMoney) {
+		int diff = m_nMoney - m_nVisibleMoney;
+		int diffAbs = Abs(diff);
+		int changeBy;
+
+		if (diffAbs > 100000)
+			changeBy = 12345;
+		else if (diffAbs > 10000)
+			changeBy = 1234;
+		else if (diffAbs > 1000)
+			changeBy = 123;
+		else if (diffAbs > 50)
+			changeBy = 42;
+		else
+			changeBy = 1;
+
+		if (diff < 0)
+			m_nVisibleMoney -= changeBy;
+		else
+			m_nVisibleMoney += changeBy;
+	}
+
+	if (!(CTimer::GetFrameCounter() & 15)) {
+		CVector2D playerPos = m_pPed->bInVehicle ? m_pPed->m_pMyVehicle->GetPosition() : m_pPed->GetPosition();
+		m_fRoadDensity = ThePaths.CalcRoadDensity(playerPos.x, playerPos.y);
+	}
+
+	m_fRoadDensity = clamp(m_fRoadDensity, 0.4f, 1.45f);
+
+	// Because vehicle enter/exit use same key binding.
+	bool enterOrExitVeh;
+	if (m_pPed->bVehExitWillBeInstant && m_pPed->bInVehicle)
+		enterOrExitVeh = CPad::GetPad(0)->ExitVehicleJustDown();
+	else
+		enterOrExitVeh = CPad::GetPad(0)->GetExitVehicle();
+
+	if (enterOrExitVeh && m_pPed->m_nPedState != PED_SNIPER_MODE && m_pPed->m_nPedState != PED_ROCKET_ODE) {
+		if (m_pPed->bInVehicle) {
+			if (!m_pRemoteVehicle) {
+				CEntity *surfaceBelowVeh = m_pPed->m_pMyVehicle->m_pCurGroundEntity;
+				if (!surfaceBelowVeh || !CBridge::ThisIsABridgeObjectMovingUp(surfaceBelowVeh->m_modelIndex)) {
+					CVehicle *veh = m_pPed->m_pMyVehicle;
+					if (!veh->IsBoat() || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
+
+						// This condition will always return true, else block was probably WIP Miami code.
+						if (veh->m_vehType != VEHICLE_TYPE_BIKE || veh->m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) {
+							if (veh->m_status != STATUS_WRECKED && veh->m_status != STATUS_TRAIN_MOVING && veh->m_nDoorLock != CARLOCK_LOCKED_PLAYER_INSIDE) {
+								if (veh->m_vecMoveSpeed.Magnitude() < 0.17f && CTimer::GetTimeScale() >= 0.5f && !veh->bIsInWater) {
+									m_pPed->SetObjective(OBJECTIVE_LEAVE_VEHICLE, veh);
+								}
+							}
+						} else {
+							CVector sth = 0.7f * veh->GetRight() + veh->GetPosition();
+							bool found = false;
+							float groundZ = CWorld::FindGroundZFor3DCoord(sth.x, sth.y, 2.0f + sth.z, &found);
+
+							if (found)
+								sth.z = 1.0f + groundZ;
+							m_pPed->m_nPedState = PED_IDLE;
+							m_pPed->SetMoveState(PEDMOVE_STILL);
+							CPed::PedSetOutCarCB(0, m_pPed);
+							CAnimManager::BlendAnimation(m_pPed->GetClump(), m_pPed->m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+							CAnimManager::BlendAnimation(m_pPed->GetClump(), ASSOCGRP_STD, ANIM_FALL_LAND, 100.0f);
+							m_pPed->GetPosition() = sth;
+							m_pPed->SetMoveState(PEDMOVE_STILL);
+							m_pPed->m_vecMoveSpeed = veh->m_vecMoveSpeed;
+						}
+					} else {
+						// The code in here was under CPed::SetExitBoat in VC, did the same for here.
+						m_pPed->SetExitBoat(veh);
+						m_pPed->bTryingToReachDryLand = true;
+					}
+				}
+			}
+		} else {
+			// Enter vehicle
+			if (CPad::GetPad(0)->ExitVehicleJustDown()) {
+				bool weAreOnBoat = false;
+				float lastCloseness = 0.0f;
+				CVehicle *carBelow = nil;
+				CEntity *surfaceBelow = m_pPed->m_pCurrentPhysSurface;
+				if (surfaceBelow && surfaceBelow->IsVehicle()) {
+					carBelow = (CVehicle*)surfaceBelow;
+					if (carBelow->IsBoat()) {
+						weAreOnBoat = true;
+						m_pPed->bOnBoat = true;
+#ifdef VC_PED_PORTS
+						if (carBelow->m_status != STATUS_WRECKED && carBelow->GetUp().z > 0.3f)
+#else
+						if (carBelow->m_status != STATUS_WRECKED)
+#endif
+							m_pPed->SetSeekBoatPosition(carBelow);
+					}
+				}
+				// Find closest car
+				if (!weAreOnBoat) {
+					float minX = m_pPed->GetPosition().x - 10.0f;
+					float maxX = 10.0f + m_pPed->GetPosition().x;
+					float minY = m_pPed->GetPosition().y - 10.0f;
+					float maxY = 10.0f + m_pPed->GetPosition().y;
+
+					int minXSector = CWorld::GetSectorIndexX(minX);
+					if (minXSector < 0) minXSector = 0;
+					int minYSector = CWorld::GetSectorIndexY(minY);
+					if (minYSector < 0) minYSector = 0;
+					int maxXSector = CWorld::GetSectorIndexX(maxX);
+					if (maxXSector > NUMSECTORS_X - 1) maxXSector = NUMSECTORS_X - 1;
+					int maxYSector = CWorld::GetSectorIndexY(maxY);
+					if (maxYSector > NUMSECTORS_Y - 1) maxYSector = NUMSECTORS_Y - 1;
+
+					CWorld::AdvanceCurrentScanCode();
+
+					for (int curY = minYSector; curY <= maxYSector; curY++) {
+						for (int curX = minXSector; curX <= maxXSector; curX++) {
+							CSector *sector = CWorld::GetSector(curX, curY);
+							FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES], m_pPed,
+								minX, minY, maxX, maxY, &lastCloseness, &carBelow);
+							FindClosestCarSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], m_pPed,
+								minX, minY, maxX, maxY, &lastCloseness, &carBelow);
+						}
+					}
+				}
+				// carBelow is now closest vehicle
+				if (carBelow && !weAreOnBoat) {
+					if (carBelow->m_status == STATUS_TRAIN_NOT_MOVING) {
+						m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, carBelow);
+					} else if (carBelow->IsBoat()) {
+						if (!carBelow->pDriver) {
+							m_pPed->m_vehEnterType = 0;
+							m_pPed->SetEnterCar(carBelow, m_pPed->m_vehEnterType);
+						}
+					} else {
+						m_pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carBelow);
+					}
+				}
+			}
+		}
+	}
+	if (m_bInRemoteMode) {
+		uint32 timeWithoutRemoteCar = CTimer::GetTimeInMilliseconds() - m_nTimeLostRemoteCar;
+		if (CTimer::GetPreviousTimeInMilliseconds() - m_nTimeLostRemoteCar < 1000 && timeWithoutRemoteCar >= 1000 && m_WBState == WBSTATE_PLAYING) {
+			TheCamera.SetFadeColour(0, 0, 0);
+			TheCamera.Fade(1.0f, 0);
+		}
+		if (timeWithoutRemoteCar > 2000) {
+			if (m_WBState == WBSTATE_PLAYING) {
+				TheCamera.RestoreWithJumpCut();
+				TheCamera.SetFadeColour(0, 0, 0);
+				TheCamera.Fade(1.0f, 1);
+				TheCamera.Process();
+				CTimer::Stop();
+				CCullZones::ForceCullZoneCoors(TheCamera.GetPosition());
+				CRenderer::RequestObjectsInFrustum();
+				CStreaming::LoadAllRequestedModels(false);
+				CTimer::Update();
+			}
+			m_bInRemoteMode = false;
+			CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle = nil;
+			if (FindPlayerVehicle()) {
+				FindPlayerVehicle()->m_status = STATUS_PLAYER;
+			}
+		}
+	}
+	if (!(CTimer::GetFrameCounter() & 31)) {
+		CVehicle *veh = FindPlayerVehicle();
+		if (veh && m_pPed->bInVehicle && veh->GetUp().z < 0.0f
+			&& veh->m_vecMoveSpeed.Magnitude() < 0.05f && veh->IsCar() && !veh->bIsInWater) {
+
+			if (veh->GetUp().z < -0.5f) {
+				m_nUpsideDownCounter += 2;
+			
+			} else {
+				m_nUpsideDownCounter++;
+			}
+		} else {
+			m_nUpsideDownCounter = 0;
+		}
+
+		if (m_nUpsideDownCounter > 6 && veh->bCanBeDamaged) {
+			veh->m_fHealth = 249.0f < veh->m_fHealth ? 249.0f : veh->m_fHealth;
+			if (veh->IsCar()) {
+				CAutomobile* car = (CAutomobile*)veh;
+				car->Damage.SetEngineStatus(225);
+				car->m_pSetOnFireEntity = nil;
+			}
+		}
+	}
+	if (FindPlayerVehicle()) {
+		CVehicle *veh = FindPlayerVehicle();
+		veh->m_nZoneLevel = -1;
+		for (int i = 0; i < ARRAY_SIZE(veh->pPassengers); i++) {
+			if (veh->pPassengers[i])
+				veh->pPassengers[i]->m_nZoneLevel = 0;
+		}
+		CStats::DistanceTravelledInVehicle += veh->m_fDistanceTravelled;
+	} else {
+		CStats::DistanceTravelledOnFoot += FindPlayerPed()->m_fDistanceTravelled;
+	}
 }
 
 STARTPATCHES
diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp
index 75536b88..6add9e0c 100644
--- a/src/core/Pools.cpp
+++ b/src/core/Pools.cpp
@@ -1,8 +1,14 @@
 #include "common.h"
 #include "patcher.h"
 #include "Pools.h"
-#include "World.h"
+
+#include "Boat.h"
+#include "CarCtrl.h"
+#include "Population.h"
 #include "ProjectileInfo.h"
+#include "Streaming.h"
+#include "Wanted.h"
+#include "World.h"
 
 CCPtrNodePool *&CPools::ms_pPtrNodePool = *(CCPtrNodePool**)0x943044;
 CEntryInfoNodePool *&CPools::ms_pEntryInfoNodePool = *(CEntryInfoNodePool**)0x941448;
@@ -14,13 +20,6 @@ CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28;
 CDummyPool *&CPools::ms_pDummyPool = *(CDummyPool**)0x8F2C18;
 CAudioScriptObjectPool *&CPools::ms_pAudioScriptObjectPool = *(CAudioScriptObjectPool**)0x8F1B6C;
 
-WRAPPER void CPools::LoadObjectPool(uint8* buf, uint32 size) { EAXJMP(0x4a2550); }
-WRAPPER void CPools::LoadPedPool(uint8* buf, uint32 size) { EAXJMP(0x4a2b50); }
-WRAPPER void CPools::LoadVehiclePool(uint8* buf, uint32 size) { EAXJMP(0x4a1b40); }
-WRAPPER void CPools::SaveObjectPool(uint8* buf, uint32 *size) { EAXJMP(0x4a22d0); }
-WRAPPER void CPools::SavePedPool(uint8* buf, uint32 *size) { EAXJMP(0x4a29b0); }
-WRAPPER void CPools::SaveVehiclePool(uint8* buf, uint32 *size) { EAXJMP(0x4a2080); }
-
 void
 CPools::Initialise(void)
 {
@@ -99,6 +98,333 @@ CPools::MakeSureSlotInObjectPoolIsEmpty(int32 slot)
 	}
 }
 
+void CPools::LoadVehiclePool(uint8* buf, uint32 size)
+{
+INITSAVEBUF
+	int nNumCars = ReadSaveBuf<int>(buf);
+	int nNumBoats = ReadSaveBuf<int>(buf);
+	for (int i = 0; i < nNumCars + nNumBoats; i++) {
+		uint32 type = ReadSaveBuf<uint32>(buf);
+		int16 model = ReadSaveBuf<int16>(buf);
+		CStreaming::RequestModel(model, STREAMFLAGS_DEPENDENCY);
+		CStreaming::LoadAllRequestedModels(false);
+		int32 slot = ReadSaveBuf<int32>(buf);
+		CVehicle* pVehicle;
+		char* vbuf = new char[max(sizeof(CAutomobile), sizeof(CBoat))];
+		if (type == VEHICLE_TYPE_BOAT) {
+			memcpy(vbuf, buf, sizeof(CBoat));
+			SkipSaveBuf(buf, sizeof(CBoat));
+			CBoat* pBoat = new(slot) CBoat(model, RANDOM_VEHICLE);
+			pVehicle = pBoat;
+			--CCarCtrl::NumRandomCars; // why?
+		}
+		else if (type == VEHICLE_TYPE_CAR) {
+			memcpy(vbuf, buf, sizeof(CAutomobile));
+			SkipSaveBuf(buf, sizeof(CAutomobile));
+			CStreaming::RequestModel(model, 0); // is it needed?
+			CStreaming::LoadAllRequestedModels(false);
+			CAutomobile* pAutomobile = new(slot) CAutomobile(model, RANDOM_VEHICLE);
+			pVehicle = pAutomobile;
+			CCarCtrl::NumRandomCars--; // why?
+			pAutomobile->Damage = ((CAutomobile*)vbuf)->Damage;
+			pAutomobile->SetupDamageAfterLoad();
+		}
+		else
+			assert(0);
+		CVehicle* pBufferVehicle = (CVehicle*)vbuf;
+		pVehicle->GetMatrix() = pBufferVehicle->GetMatrix();
+		pVehicle->VehicleCreatedBy = pBufferVehicle->VehicleCreatedBy;
+		pVehicle->m_currentColour1 = pBufferVehicle->m_currentColour1;
+		pVehicle->m_currentColour2 = pBufferVehicle->m_currentColour2;
+		pVehicle->m_nAlarmState = pBufferVehicle->m_nAlarmState;
+		pVehicle->m_nNumMaxPassengers = pBufferVehicle->m_nNumMaxPassengers;
+		pVehicle->field_1D0[0] = pBufferVehicle->field_1D0[0];
+		pVehicle->field_1D0[1] = pBufferVehicle->field_1D0[1];
+		pVehicle->field_1D0[2] = pBufferVehicle->field_1D0[2];
+		pVehicle->field_1D0[3] = pBufferVehicle->field_1D0[3];
+		pVehicle->m_fSteerAngle = pBufferVehicle->m_fSteerAngle;
+		pVehicle->m_fGasPedal = pBufferVehicle->m_fGasPedal;
+		pVehicle->m_fBrakePedal = pBufferVehicle->m_fBrakePedal;
+		pVehicle->bIsLawEnforcer = pBufferVehicle->bIsLawEnforcer;
+		pVehicle->bIsLocked = pBufferVehicle->bIsLocked;
+		pVehicle->bEngineOn = pBufferVehicle->bEngineOn;
+		pVehicle->bIsHandbrakeOn = pBufferVehicle->bIsHandbrakeOn;
+		pVehicle->bLightsOn = pBufferVehicle->bLightsOn;
+		pVehicle->bFreebies = pBufferVehicle->bFreebies;
+		pVehicle->m_fHealth = pBufferVehicle->m_fHealth;
+		pVehicle->m_nCurrentGear = pBufferVehicle->m_nCurrentGear;
+		pVehicle->m_fChangeGearTime = pBufferVehicle->m_fChangeGearTime;
+		pVehicle->m_nTimeOfDeath = pBufferVehicle->m_nTimeOfDeath;
+#ifdef FIX_BUGS //must be copypaste
+		pVehicle->m_nBombTimer = pBufferVehicle->m_nBombTimer;
+#else
+		pVehicle->m_nTimeOfDeath = pBufferVehicle->m_nTimeOfDeath;
+#endif
+		pVehicle->m_nDoorLock = pBufferVehicle->m_nDoorLock;
+		pVehicle->m_status = pBufferVehicle->m_status;
+		pVehicle->m_type = pBufferVehicle->m_type;
+		(pVehicle->GetAddressOfEntityProperties())[0] = (pBufferVehicle->GetAddressOfEntityProperties())[0];
+		(pVehicle->GetAddressOfEntityProperties())[1] = (pBufferVehicle->GetAddressOfEntityProperties())[1];
+		pVehicle->AutoPilot = pBufferVehicle->AutoPilot;
+		CWorld::Add(pVehicle);
+		delete[] vbuf;
+	}
+VALIDATESAVEBUF(size)
+}
+
+void CPools::SaveVehiclePool(uint8* buf, uint32* size)
+{
+INITSAVEBUF
+	int nNumCars = 0;
+	int nNumBoats = 0;
+	int nPoolSize = GetVehiclePool()->GetSize();
+	for (int i = 0; i < nPoolSize; i++) {
+		CVehicle* pVehicle = GetVehiclePool()->GetSlot(i);
+		if (!pVehicle)
+			continue;
+		bool bHasPassenger = false;
+		for (int j = 0; j < ARRAY_SIZE(pVehicle->pPassengers); j++) {
+			if (pVehicle->pPassengers[i])
+				bHasPassenger = true;
+		}
+		if (!pVehicle->pDriver && !bHasPassenger) {
+			if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE)
+				++nNumCars;
+			if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE)
+				++nNumBoats;
+		}
+	}
+	*size = nNumCars * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + sizeof(CAutomobile)) + sizeof(int) +
+		nNumBoats * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + sizeof(CBoat)) + sizeof(int);
+	WriteSaveBuf(buf, nNumCars);
+	WriteSaveBuf(buf, nNumBoats);
+	for (int i = 0; i < nPoolSize; i++) {
+		CVehicle* pVehicle = GetVehiclePool()->GetSlot(i);
+		if (!pVehicle)
+			continue;
+		bool bHasPassenger = false;
+		for (int j = 0; j < ARRAY_SIZE(pVehicle->pPassengers); j++) {
+			if (pVehicle->pPassengers[j])
+				bHasPassenger = true;
+		}
+		if (!pVehicle->pDriver && !bHasPassenger) {
+			if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
+				WriteSaveBuf(buf, (uint32)pVehicle->m_vehType);
+				WriteSaveBuf(buf, pVehicle->m_modelIndex);
+				WriteSaveBuf(buf, GetVehicleRef(pVehicle));
+				memcpy(buf, pVehicle, sizeof(CAutomobile));
+				SkipSaveBuf(buf, sizeof(CAutomobile));
+			}
+			if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) {
+				WriteSaveBuf(buf, (uint32)pVehicle->m_vehType);
+				WriteSaveBuf(buf, pVehicle->m_modelIndex);
+				WriteSaveBuf(buf, GetVehicleRef(pVehicle));
+				memcpy(buf, pVehicle, sizeof(CBoat));
+				SkipSaveBuf(buf, sizeof(CBoat));
+			}
+		}
+	}
+VALIDATESAVEBUF(*size)
+}
+
+void CPools::SaveObjectPool(uint8* buf, uint32* size)
+{
+INITSAVEBUF
+	CProjectileInfo::RemoveAllProjectiles();
+	CObject::DeleteAllTempObjects();
+	int nObjects = 0;
+	int nPoolSize = GetObjectPool()->GetSize();
+	for (int i = 0; i < nPoolSize; i++) {
+		CObject* pObject = GetObjectPool()->GetSlot(i);
+		if (!pObject)
+			continue;
+		if (pObject->ObjectCreatedBy == MISSION_OBJECT)
+			++nObjects;
+	}
+	*size = nObjects * (sizeof(int16) + sizeof(int) + sizeof(CCompressedMatrixNotAligned) + sizeof(uint32) +
+		sizeof(float) + sizeof(CCompressedMatrixNotAligned) + sizeof(uint32) + sizeof(int8) + 7 * sizeof(bool) + sizeof(float) +
+		sizeof(int8) + sizeof(int8) + sizeof(uint32) + 2 * sizeof(uint32)) + sizeof(int);
+	WriteSaveBuf(buf, nObjects);
+	for (int i = 0; i < nPoolSize; i++) {
+		CObject* pObject = GetObjectPool()->GetSlot(i);
+		if (!pObject)
+			continue;
+		if (pObject->ObjectCreatedBy == MISSION_OBJECT) {
+			bool bIsPickup = pObject->bIsPickup;
+			bool bFlag2 = pObject->m_obj_flag2;
+			bool bOutOfStock = pObject->bOutOfStock;
+			bool bGlassCracked = pObject->bGlassCracked;
+			bool bGlassBroken = pObject->bGlassBroken;
+			bool bHasBeenDamaged = pObject->bHasBeenDamaged;
+			bool bUseVehicleColours = pObject->bUseVehicleColours;
+			CCompressedMatrixNotAligned tmp;
+			WriteSaveBuf(buf, pObject->m_modelIndex);
+			WriteSaveBuf(buf, GetObjectRef(pObject));
+			tmp.CompressFromFullMatrix(pObject->GetMatrix());
+			WriteSaveBuf(buf, tmp);
+			WriteSaveBuf(buf, (uint32)0); // game writes ununitialized data here
+			WriteSaveBuf(buf, pObject->m_fUprootLimit);
+			tmp.CompressFromFullMatrix(pObject->m_objectMatrix);
+			WriteSaveBuf(buf, tmp);
+			WriteSaveBuf(buf, (uint32)0); // same
+			WriteSaveBuf(buf, pObject->ObjectCreatedBy);
+			WriteSaveBuf(buf, bIsPickup);
+			WriteSaveBuf(buf, bFlag2);
+			WriteSaveBuf(buf, bOutOfStock);
+			WriteSaveBuf(buf, bGlassCracked);
+			WriteSaveBuf(buf, bGlassBroken);
+			WriteSaveBuf(buf, bHasBeenDamaged);
+			WriteSaveBuf(buf, bUseVehicleColours);
+			WriteSaveBuf(buf, pObject->m_fCollisionDamageMultiplier);
+			WriteSaveBuf(buf, pObject->m_nCollisionDamageEffect);
+			WriteSaveBuf(buf, pObject->m_nSpecialCollisionResponseCases);
+			WriteSaveBuf(buf, pObject->m_nEndOfLifeTime);
+			WriteSaveBuf(buf, (pObject->GetAddressOfEntityProperties())[0]);
+			WriteSaveBuf(buf, (pObject->GetAddressOfEntityProperties())[1]);
+		}
+	}
+VALIDATESAVEBUF(*size)
+}
+
+void CPools::LoadObjectPool(uint8* buf, uint32 size)
+{
+INITSAVEBUF
+	int nObjects = ReadSaveBuf<int>(buf);
+	for (int i = 0; i < nObjects; i++) {
+		int16 mi = ReadSaveBuf<int16>(buf);
+		int ref = ReadSaveBuf<int>(buf);
+		char* obuf = new char[sizeof(CObject)];
+		CObject* pBufferObject = (CObject*)obuf;
+		CCompressedMatrixNotAligned tmp;
+		tmp = ReadSaveBuf<CCompressedMatrixNotAligned>(buf);
+		tmp.DecompressIntoFullMatrix(pBufferObject->GetMatrix());
+		ReadSaveBuf<uint32>(buf);
+		pBufferObject->m_fUprootLimit = ReadSaveBuf<float>(buf);
+		tmp = ReadSaveBuf<CCompressedMatrixNotAligned>(buf);
+		tmp.DecompressIntoFullMatrix(pBufferObject->m_objectMatrix);
+		ReadSaveBuf<uint32>(buf);
+		pBufferObject->ObjectCreatedBy = ReadSaveBuf<int8>(buf);
+		pBufferObject->bIsPickup = ReadSaveBuf<bool>(buf);
+		pBufferObject->m_flagE2 = ReadSaveBuf<bool>(buf);
+		pBufferObject->bOutOfStock = ReadSaveBuf<bool>(buf);
+		pBufferObject->bGlassCracked = ReadSaveBuf<bool>(buf);
+		pBufferObject->bGlassBroken = ReadSaveBuf<bool>(buf);
+		pBufferObject->bHasBeenDamaged = ReadSaveBuf<bool>(buf);
+		pBufferObject->bUseVehicleColours = ReadSaveBuf<bool>(buf);
+		pBufferObject->m_fCollisionDamageMultiplier = ReadSaveBuf<float>(buf);
+		pBufferObject->m_nCollisionDamageEffect = ReadSaveBuf<uint8>(buf);
+		pBufferObject->m_nSpecialCollisionResponseCases = ReadSaveBuf<uint8>(buf);
+		pBufferObject->m_nEndOfLifeTime = ReadSaveBuf<uint32>(buf);
+		(pBufferObject->GetAddressOfEntityProperties())[0] = ReadSaveBuf<uint32>(buf);
+		(pBufferObject->GetAddressOfEntityProperties())[1] = ReadSaveBuf<uint32>(buf);
+		if (GetObjectPool()->GetSlot(ref >> 8))
+			CPopulation::ConvertToDummyObject(GetObjectPool()->GetSlot(ref >> 8));
+		CObject* pObject = new(ref) CObject(mi, false);
+		pObject->GetMatrix() = pBufferObject->GetMatrix();
+		pObject->m_fUprootLimit = pBufferObject->m_fUprootLimit;
+		pObject->m_objectMatrix = pBufferObject->m_objectMatrix;
+		pObject->ObjectCreatedBy = pBufferObject->ObjectCreatedBy;
+		pObject->bIsPickup = pBufferObject->bIsPickup;
+		pObject->m_flagE2 = pBufferObject->m_flagE2;
+		pObject->bOutOfStock = pBufferObject->bOutOfStock;
+		pObject->bGlassCracked = pBufferObject->bGlassCracked;
+		pObject->bGlassBroken = pBufferObject->bGlassBroken;
+		pObject->bHasBeenDamaged = pBufferObject->bHasBeenDamaged;
+		pObject->bUseVehicleColours = pBufferObject->bUseVehicleColours;
+		pObject->m_fCollisionDamageMultiplier = pBufferObject->m_fCollisionDamageMultiplier;
+		pObject->m_nCollisionDamageEffect = pBufferObject->m_nCollisionDamageEffect;
+		pObject->m_nSpecialCollisionResponseCases = pBufferObject->m_nSpecialCollisionResponseCases;
+		pObject->m_nEndOfLifeTime = pBufferObject->m_nEndOfLifeTime;
+		(pObject->GetAddressOfEntityProperties())[0] = (pBufferObject->GetAddressOfEntityProperties())[0];
+		(pObject->GetAddressOfEntityProperties())[1] = (pBufferObject->GetAddressOfEntityProperties())[1];
+		pObject->bHasCollided = false;
+		CWorld::Add(pObject);
+		delete[] obuf;
+	}
+VALIDATESAVEBUF(size)
+}
+
+void CPools::SavePedPool(uint8* buf, uint32* size)
+{
+INITSAVEBUF
+	int nNumPeds = 0;
+	int nPoolSize = GetPedPool()->GetSize();
+	for (int i = 0; i < nPoolSize; i++) {
+		CPed* pPed = GetPedPool()->GetSlot(i);
+		if (!pPed)
+			continue;
+		if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1)
+			nNumPeds++;
+	}
+	*size = sizeof(int) + nNumPeds * (sizeof(uint32) + sizeof(int16) + sizeof(int) + sizeof(CPlayerPed) +
+		sizeof(CWanted::MaximumWantedLevel) + sizeof(CWanted::nMaximumWantedLevel) + MAX_MODEL_NAME);
+	WriteSaveBuf(buf, nNumPeds);
+	for (int i = 0; i < nPoolSize; i++) {
+		CPed* pPed = GetPedPool()->GetSlot(i);
+		if (!pPed)
+			continue;
+		if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1) {
+			WriteSaveBuf(buf, pPed->m_nPedType);
+			WriteSaveBuf(buf, pPed->m_modelIndex);
+			WriteSaveBuf(buf, GetPedRef(pPed));
+			memcpy(buf, pPed, sizeof(CPlayerPed));
+			SkipSaveBuf(buf, sizeof(CPlayerPed));
+			WriteSaveBuf(buf, CWanted::MaximumWantedLevel);
+			WriteSaveBuf(buf, CWanted::nMaximumWantedLevel);
+			memcpy(buf, CModelInfo::GetModelInfo(pPed->GetModelIndex())->GetName(), MAX_MODEL_NAME);
+			SkipSaveBuf(buf, MAX_MODEL_NAME);
+		}
+	}
+VALIDATESAVEBUF(*size);
+}
+
+void CPools::LoadPedPool(uint8* buf, uint32 size)
+{
+INITSAVEBUF
+	int nPeds = ReadSaveBuf<int>(buf);
+	for (int i = 0; i < nPeds; i++) {
+		uint32 pedtype = ReadSaveBuf<uint32>(buf);
+		int16 model = ReadSaveBuf<int16>(buf);
+		int ref = ReadSaveBuf<int>(buf);
+		char* pbuf = new char[sizeof(CPlayerPed)];
+		CPlayerPed* pBufferPlayer = (CPlayerPed*)pbuf;
+		CPed* pPed;
+		char name[MAX_MODEL_NAME];
+		// the code implies that there was idea to load non-player ped
+		if (pedtype == PEDTYPE_PLAYER1) { // always true
+			memcpy(pbuf, buf, sizeof(CPlayerPed));
+			SkipSaveBuf(buf, sizeof(CPlayerPed));
+			CWanted::MaximumWantedLevel = ReadSaveBuf<int32>(buf);
+			CWanted::nMaximumWantedLevel = ReadSaveBuf<int32>(buf);
+			memcpy(name, buf, MAX_MODEL_NAME);
+			SkipSaveBuf(buf, MAX_MODEL_NAME);
+		}
+		CStreaming::RequestSpecialModel(model, name, STREAMFLAGS_DONT_REMOVE);
+		CStreaming::LoadAllRequestedModels(false);
+		if (pedtype == PEDTYPE_PLAYER1) {
+			CPlayerPed* pPlayerPed = new(ref) CPlayerPed();
+			for (int i = 0; i < ARRAY_SIZE(pPlayerPed->m_nTargettableObjects); i++)
+				pPlayerPed->m_nTargettableObjects[i] = pBufferPlayer->m_nTargettableObjects[i];
+			pPlayerPed->m_fMaxStamina = pBufferPlayer->m_fMaxStamina;
+			pPed = pPlayerPed;
+		}
+		pPed->GetPosition() = pBufferPlayer->GetPosition();
+		pPed->m_fHealth = pBufferPlayer->m_fHealth;
+		pPed->m_fArmour = pBufferPlayer->m_fArmour;
+		pPed->CharCreatedBy = pBufferPlayer->CharCreatedBy;
+		pPed->m_currentWeapon = 0;
+		pPed->m_maxWeaponTypeAllowed = pBufferPlayer->m_maxWeaponTypeAllowed;
+		for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++)
+			pPed->m_weapons[i] = pBufferPlayer->m_weapons[i];
+		if (pedtype == PEDTYPE_PLAYER1) {
+			pPed->m_wepAccuracy = 100;
+			CWorld::Players[0].m_pPed = (CPlayerPed*)pPed;
+		}
+		CWorld::Add(pPed);
+		delete[] pbuf;
+	}
+VALIDATESAVEBUF(size)
+}
 
 STARTPATCHES
 	InjectHook(0x4A1770, CPools::Initialise, PATCH_JUMP);
@@ -111,4 +437,7 @@ STARTPATCHES
 	InjectHook(0x4A1B00, CPools::GetObjectRef, PATCH_JUMP);
 	InjectHook(0x4A1B20, CPools::GetObject, PATCH_JUMP);
 	InjectHook(0x4A2DB0, CPools::MakeSureSlotInObjectPoolIsEmpty, PATCH_JUMP);
+	InjectHook(0x4A1B40, CPools::LoadVehiclePool, PATCH_JUMP);
+	InjectHook(0x4A2550, CPools::LoadObjectPool, PATCH_JUMP);
+	InjectHook(0x4A2B50, CPools::LoadPedPool, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/core/Profile.cpp b/src/core/Profile.cpp
new file mode 100644
index 00000000..56584d12
--- /dev/null
+++ b/src/core/Profile.cpp
@@ -0,0 +1,71 @@
+#include "common.h"
+#include "Profile.h"
+
+#ifndef MASTER
+float CProfile::ms_afStartTime[NUM_PROFILES];
+float CProfile::ms_afCumulativeTime[NUM_PROFILES];
+float CProfile::ms_afEndTime[NUM_PROFILES];
+float CProfile::ms_afMaxEndTime[NUM_PROFILES];
+float CProfile::ms_afMaxCumulativeTime[NUM_PROFILES];
+char *CProfile::ms_pProfileString[NUM_PROFILES];
+RwRGBA CProfile::ms_aBarColours[NUM_PROFILES];
+
+void CProfile::Initialise()
+{
+	ms_afMaxEndTime[PROFILE_FRAME_RATE] = 0.0f;
+	ms_afMaxEndTime[PROFILE_PHYSICS] = 0.0f;
+	ms_afMaxEndTime[PROFILE_COLLISION] = 0.0f;
+	ms_afMaxEndTime[PROFILE_PED_AI] = 0.0f;
+	ms_afMaxEndTime[PROFILE_PROCESSING_TIME] = 0.0f;
+	ms_afMaxEndTime[PROFILE_RENDERING_TIME] = 0.0f;
+	ms_afMaxEndTime[PROFILE_TOTAL] = 0.0f;
+
+	ms_pProfileString[PROFILE_FRAME_RATE] = "Frame rate";
+	ms_pProfileString[PROFILE_PHYSICS] = "Physics";
+	ms_pProfileString[PROFILE_COLLISION] = "Collision";
+	ms_pProfileString[PROFILE_PED_AI] = "Ped AI";
+	ms_pProfileString[PROFILE_PROCESSING_TIME] = "Processing time";
+	ms_pProfileString[PROFILE_RENDERING_TIME] = "Rendering time";
+	ms_pProfileString[PROFILE_TOTAL] = "Total";
+
+	ms_afMaxCumulativeTime[PROFILE_FRAME_RATE] = 0.0f;
+	ms_afMaxCumulativeTime[PROFILE_PHYSICS] = 0.0f;
+	ms_afMaxCumulativeTime[PROFILE_COLLISION] = 0.0f;
+	ms_afMaxCumulativeTime[PROFILE_PED_AI] = 0.0f;
+	ms_afMaxCumulativeTime[PROFILE_PROCESSING_TIME] = 0.0f;
+	ms_afMaxCumulativeTime[PROFILE_RENDERING_TIME] = 0.0f;
+	ms_afMaxCumulativeTime[PROFILE_TOTAL] = 0.0f;
+
+	ms_aBarColours[PROFILE_PHYSICS] = { 0, 127, 255, 255 };
+	ms_aBarColours[PROFILE_COLLISION] = { 0, 255, 255, 255 };
+	ms_aBarColours[PROFILE_PED_AI] = { 255, 0, 0, 255 };
+	ms_aBarColours[PROFILE_PROCESSING_TIME] = { 0, 255, 0, 255 };
+	ms_aBarColours[PROFILE_RENDERING_TIME] = { 0, 0, 255, 255 };
+	ms_aBarColours[PROFILE_TOTAL] = { 255, 255, 255, 255 };
+}
+
+void CProfile::SuspendProfile(eProfile profile)
+{
+	ms_afEndTime[profile] = -ms_afStartTime[profile];
+	ms_afCumulativeTime[profile] -= ms_afStartTime[profile];
+}
+
+void CProfile::ShowResults()
+{
+	ms_afMaxEndTime[PROFILE_FRAME_RATE] = max(ms_afMaxEndTime[PROFILE_FRAME_RATE], ms_afEndTime[PROFILE_FRAME_RATE]);
+	ms_afMaxEndTime[PROFILE_PHYSICS] = max(ms_afMaxEndTime[PROFILE_PHYSICS], ms_afEndTime[PROFILE_PHYSICS]);
+	ms_afMaxEndTime[PROFILE_COLLISION] = max(ms_afMaxEndTime[PROFILE_COLLISION], ms_afEndTime[PROFILE_COLLISION]);
+	ms_afMaxEndTime[PROFILE_PED_AI] = max(ms_afMaxEndTime[PROFILE_PED_AI], ms_afEndTime[PROFILE_PED_AI]);
+	ms_afMaxEndTime[PROFILE_PROCESSING_TIME] = max(ms_afMaxEndTime[PROFILE_PROCESSING_TIME], ms_afEndTime[PROFILE_PROCESSING_TIME]);
+	ms_afMaxEndTime[PROFILE_RENDERING_TIME] = max(ms_afMaxEndTime[PROFILE_RENDERING_TIME], ms_afEndTime[PROFILE_RENDERING_TIME]);
+	ms_afMaxEndTime[PROFILE_TOTAL] = max(ms_afMaxEndTime[PROFILE_TOTAL], ms_afEndTime[PROFILE_TOTAL]);
+
+	ms_afMaxCumulativeTime[PROFILE_FRAME_RATE] = max(ms_afMaxCumulativeTime[PROFILE_FRAME_RATE], ms_afCumulativeTime[PROFILE_FRAME_RATE]);
+	ms_afMaxCumulativeTime[PROFILE_PHYSICS] = max(ms_afMaxCumulativeTime[PROFILE_PHYSICS], ms_afCumulativeTime[PROFILE_PHYSICS]);
+	ms_afMaxCumulativeTime[PROFILE_COLLISION] = max(ms_afMaxCumulativeTime[PROFILE_COLLISION], ms_afCumulativeTime[PROFILE_COLLISION]);
+	ms_afMaxCumulativeTime[PROFILE_PED_AI] = max(ms_afMaxCumulativeTime[PROFILE_PED_AI], ms_afCumulativeTime[PROFILE_PED_AI]);
+	ms_afMaxCumulativeTime[PROFILE_PROCESSING_TIME] = max(ms_afMaxCumulativeTime[PROFILE_PROCESSING_TIME], ms_afCumulativeTime[PROFILE_PROCESSING_TIME]);
+	ms_afMaxCumulativeTime[PROFILE_RENDERING_TIME] = max(ms_afMaxCumulativeTime[PROFILE_RENDERING_TIME], ms_afCumulativeTime[PROFILE_RENDERING_TIME]);
+	ms_afMaxCumulativeTime[PROFILE_TOTAL] = max(ms_afMaxCumulativeTime[PROFILE_TOTAL], ms_afCumulativeTime[PROFILE_TOTAL]);
+}
+#endif
\ No newline at end of file
diff --git a/src/core/Profile.h b/src/core/Profile.h
new file mode 100644
index 00000000..d2e8054b
--- /dev/null
+++ b/src/core/Profile.h
@@ -0,0 +1,28 @@
+#pragma once
+
+enum eProfile
+{
+	PROFILE_FRAME_RATE,
+	PROFILE_PHYSICS,
+	PROFILE_COLLISION,
+	PROFILE_PED_AI,
+	PROFILE_PROCESSING_TIME,
+	PROFILE_RENDERING_TIME,
+	PROFILE_TOTAL,
+	NUM_PROFILES,
+};
+
+class CProfile
+{
+	static float ms_afStartTime[NUM_PROFILES];
+	static float ms_afCumulativeTime[NUM_PROFILES];
+	static float ms_afEndTime[NUM_PROFILES];
+	static float ms_afMaxEndTime[NUM_PROFILES];
+	static float ms_afMaxCumulativeTime[NUM_PROFILES];
+	static char *ms_pProfileString[NUM_PROFILES];
+	static RwRGBA ms_aBarColours[NUM_PROFILES];
+public:
+	static void Initialise();
+	static void SuspendProfile(eProfile profile);
+	static void ShowResults();
+};
\ No newline at end of file
diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp
index f1d8ec96..154e7e9a 100644
--- a/src/core/Radar.cpp
+++ b/src/core/Radar.cpp
@@ -1,1307 +1,1506 @@
-#include "config.h"
-#include "common.h"
-#include "patcher.h"
-#include "RwHelper.h"
-#include "Radar.h"
-#include "Camera.h"
-#include "Hud.h"
-#include "World.h"
-#include "Frontend.h"
-#include "General.h"
-#include "Vehicle.h"
-#include "Pools.h"
-#include "Script.h"
-#include "TxdStore.h"
-#include "World.h"
-#include "Streaming.h"
-#include "SpecialFX.h"
-
-float &CRadar::m_radarRange = *(float*)0x8E281C;
-CBlip (&CRadar::ms_RadarTrace)[NUMRADARBLIPS] = *(CBlip(*)[NUMRADARBLIPS]) * (uintptr*)0x6ED5E0;
-CVector2D &vec2DRadarOrigin = *(CVector2D*)0x6299B8;
-int32 gRadarTxdIds[64];// = (int*)0x6299C0;
-
-CSprite2d CRadar::AsukaSprite;// = *(CSprite2d*)0x8F1A40;
-CSprite2d CRadar::BombSprite;// = (CSprite2d*)0x8F5FB4;
-CSprite2d CRadar::CatSprite;// = (CSprite2d*)0x885B24;
-CSprite2d CRadar::CentreSprite;// = (CSprite2d*)0x8F6268;
-CSprite2d CRadar::CopcarSprite;// = (CSprite2d*)0x8F1A2C;
-CSprite2d CRadar::DonSprite;// = (CSprite2d*)0x8F2BE0;
-CSprite2d CRadar::EightSprite;// = (CSprite2d*)0x8F2BCC;
-CSprite2d CRadar::ElSprite;// = (CSprite2d*)0x8F1B80;
-CSprite2d CRadar::IceSprite;// = (CSprite2d*)0x9415FC;
-CSprite2d CRadar::JoeySprite;// = (CSprite2d*)0x8F2C00;
-CSprite2d CRadar::KenjiSprite;// = (CSprite2d*)0x8F2C68;
-CSprite2d CRadar::LizSprite;// = (CSprite2d*)0x8F5830;
-CSprite2d CRadar::LuigiSprite;// = (CSprite2d*)0x8F1A3C;
-CSprite2d CRadar::NorthSprite;// = (CSprite2d*)0x8F6274;
-CSprite2d CRadar::RaySprite;// = (CSprite2d*)0x8E2A7C;
-CSprite2d CRadar::SalSprite;// = (CSprite2d*)0x8F29EC;
-CSprite2d CRadar::SaveSprite;// = (CSprite2d*)0x8F5F74;
-CSprite2d CRadar::SpraySprite;// = (CSprite2d*)0x94307C;
-CSprite2d CRadar::TonySprite;// = (CSprite2d*)0x885B58;
-CSprite2d CRadar::WeaponSprite;// = (CSprite2d*)0x941534;
-
-CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { 
-	nil,
-	&AsukaSprite,
-	&BombSprite,
-	&CatSprite,
-	&CentreSprite,
-	&CopcarSprite,
-	&DonSprite,
-	&EightSprite,
-	&ElSprite,
-	&IceSprite,
-	&JoeySprite,
-	&KenjiSprite,
-	&LizSprite,
-	&LuigiSprite,
-	&NorthSprite,
-	&RaySprite,
-	&SalSprite,
-	&SaveSprite,
-	&SpraySprite,
-	&TonySprite,
-	&WeaponSprite
-};
-
-#define RADAR_NUM_TILES (8)
-#define RADAR_TILE_SIZE (WORLD_SIZE_X / RADAR_NUM_TILES)
-static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square");
-
-#define RADAR_MIN_RANGE (120.0f)
-#define RADAR_MAX_RANGE (350.0f)
-#define RADAR_MIN_SPEED (0.3f)
-#define RADAR_MAX_SPEED (0.9f)
-
-uint8 CRadar::CalculateBlipAlpha(float dist)
-{
-	if (dist <= 1.0f)
-		return 255;
-
-	if (dist <= 5.0f)
-		return (128.0f * ((dist - 1.0f) / 4.0f)) + ((1.0f - (dist - 1.0f) / 4.0f) * 255.0f);
-
-	return 128;
-}
-
-void CRadar::ChangeBlipBrightness(int32 i, int32 bright)
-{
-	int index = GetActualBlipArrayIndex(i);
-	if (index != -1)
-		ms_RadarTrace[index].m_bDim = bright != 1;
-}
-
-void CRadar::ChangeBlipColour(int32 i, int32 color)
-{
-	int index = GetActualBlipArrayIndex(i);
-	if (index != -1)
-		ms_RadarTrace[index].m_nColor = color;
-}
-
-void CRadar::ChangeBlipDisplay(int32 i, eBlipDisplay display)
-{
-	int index = GetActualBlipArrayIndex(i);
-	if (index != -1)
-		ms_RadarTrace[index].m_eBlipDisplay = display;
-}
-
-void CRadar::ChangeBlipScale(int32 i, int32 scale)
-{
-	int index = GetActualBlipArrayIndex(i);
-	if (index != -1)
-		ms_RadarTrace[index].m_wScale = scale;
-}
-
-void CRadar::ClearBlip(int32 i)
-{
-	int index = GetActualBlipArrayIndex(i);
-	if (index != -1) {
-		SetRadarMarkerState(index, false);
-		ms_RadarTrace[index].m_bInUse = false;
-		ms_RadarTrace[index].m_eBlipType = BLIP_NONE;
-		ms_RadarTrace[index].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
-		ms_RadarTrace[index].m_IconID = RADAR_SPRITE_NONE;
-	}
-}
-
-void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
-{
-	for (int i = 0; i < NUMRADARBLIPS; i++) {
-		if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) {
-			SetRadarMarkerState(i, false);
-			ms_RadarTrace[i].m_bInUse = false;
-			ms_RadarTrace[i].m_eBlipType = BLIP_NONE;
-			ms_RadarTrace[i].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
-			ms_RadarTrace[i].m_IconID = RADAR_SPRITE_NONE;
-		}
-	};
-}
-
-// Why not a proper clipping algorithm?
-int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
-{
-	CVector2D corners[4] = {
-		{  1.0f, -1.0f },	// top right
-		{  1.0f,  1.0f },	// bottom right
-		{ -1.0f,  1.0f },	// bottom left
-		{ -1.0f, -1.0f },	// top left
-	};
-	CVector2D tmp;
-	int i, j, n;
-	int laste, e, e1, e2;;
-	bool inside[4];
-
-	for (i = 0; i < 4; i++)
-		inside[i] = IsPointInsideRadar(rect[i]);
-
-	laste = -1;
-	n = 0;
-	for (i = 0; i < 4; i++)
-		if (inside[i]) {
-			// point is inside, just add
-			poly[n++] = rect[i];
-		}
-		else {
-			// point is outside but line to this point might be clipped
-			e1 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 4 - 1) % 4]);
-			if (e1 != -1) {
-				laste = e1;
-				n++;
-			}
-			// and line from this point might be clipped as well
-			e2 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 1) % 4]);
-			if (e2 != -1) {
-				if (e1 == -1) {
-					// if other line wasn't clipped, i.e. it was complete outside,
-					// we may have to insert another vertex if last clipped line
-					// was on a different edge
-
-					// find the last intersection if we haven't seen it yet
-					if (laste == -1)
-						for (j = 3; j >= i; j--) {
-							// game uses an if here for j == 0
-							e = LineRadarBoxCollision(tmp, rect[j], rect[(j + 4 - 1) % 4]);
-							if (e != -1) {
-								laste = e;
-								break;
-							}
-						}
-					assert(laste != -1);
-
-					// insert corners that were skipped
-					tmp = poly[n];
-					for (e = laste; e != e2; e = (e + 1) % 4)
-						poly[n++] = corners[e];
-					poly[n] = tmp;
-				}
-				n++;
-			}
-		}
-
-	if (n == 0) {
-		// If no points, either the rectangle is completely outside or completely surrounds the radar
-		// no idea what's going on here...
-		float m = (rect[0].y - rect[1].y) / (rect[0].x - rect[1].x);
-		if ((m*rect[3].x - rect[3].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
-			m = (rect[0].y - rect[3].y) / (rect[0].x - rect[3].x);
-			if ((m*rect[1].x - rect[1].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
-				poly[0] = corners[0];
-				poly[1] = corners[1];
-				poly[2] = corners[2];
-				poly[3] = corners[3];
-				n = 4;
-			}
-		}
-	}
-
-	return n;
-}
-
-bool CRadar::DisplayThisBlip(int32 counter)
-{
-	switch (ms_RadarTrace[counter].m_IconID) {
-	case RADAR_SPRITE_BOMB:
-	case RADAR_SPRITE_SPRAY:
-	case RADAR_SPRITE_WEAPON:
-		return true;
-	default:
-		return false;
-	}
-}
-
-void CRadar::Draw3dMarkers()
-{
-	for (int i = 0; i < NUMRADARBLIPS; i++) {
-		if (ms_RadarTrace[i].m_bInUse) {
-			switch (ms_RadarTrace[i].m_eBlipType) {
-			case BLIP_CAR:
-			{
-				CEntity *entity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[i].m_nEntityHandle);
-				if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-					CVector pos = entity->GetPosition();
-					pos.z += 1.2f * CModelInfo::GetModelInfo(entity->GetModelIndex())->GetColModel()->boundingBox.max.z + 2.5f;
-					C3dMarkers::PlaceMarker(i | (ms_RadarTrace[i].m_BlipIndex << 16), 1, pos, 2.5f, 0, 128, 255, 255, 1024, 0.2f, 5);
-				}
-				break;
-			}
-			case BLIP_CHAR:
-			{
-				CEntity *entity = CPools::GetPedPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle);
-				if (entity != nil) {
-					if (((CPed*)entity)->InVehicle())
-						entity = ((CPed * )entity)->m_pMyVehicle;
-				}
-				if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-					CVector pos = entity->GetPosition();
-					pos.z += 3.0f;
-					C3dMarkers::PlaceMarker(i | (ms_RadarTrace[i].m_BlipIndex << 16), 1, pos, 1.5f, 0, 128, 255, 255, 1024, 0.2f, 5);
-				}
-				break;
-			}
-			case BLIP_OBJECT:
-			{
-				CEntity *entity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle);
-				if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-					CVector pos = entity->GetPosition();
-					pos.z += CModelInfo::GetModelInfo(entity->GetModelIndex())->GetColModel()->boundingBox.max.z + 1.0f + 1.0f;
-					C3dMarkers::PlaceMarker(i | (ms_RadarTrace[i].m_BlipIndex << 16), 1, pos, 1.0f, 0, 128, 255, 255, 1024, 0.2f, 5);
-				}
-				break;
-			}
-			case BLIP_COORD:
-				break;
-			case BLIP_CONTACT_POINT:
-				if (!CTheScripts::IsPlayerOnAMission()) {
-					if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY)
-						C3dMarkers::PlaceMarkerSet(i | (ms_RadarTrace[i].m_BlipIndex << 16), 4, ms_RadarTrace[i].m_vecPos, 2.0f, 0, 128, 255, 128, 2048, 0.2f, 0);
-				}
-				break;
-			}
-		}
-	}
-}
-
-void CRadar::DrawBlips()
-{
-	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
-		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
-		RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
-		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
-		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
-		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
-
-		CVector2D out;
-		CVector2D in = CVector2D(0.0f, 0.0f);
-		TransformRadarPointToScreenSpace(out, in);
-
-		float angle;
-		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN)
-			angle = PI + FindPlayerHeading();
-#ifdef FIX_BUGS
-		else if (TheCamera.GetLookDirection() != LOOKING_FORWARD)
-			angle = FindPlayerHeading() - (PI + (TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind).Heading());
-#endif
-		else
-			angle = FindPlayerHeading() - (PI + TheCamera.GetForward().Heading());
-
-		DrawRotatingRadarSprite(&CentreSprite, out.x, out.y, angle, 255);
-
-		CVector2D vec2d;
-		vec2d.x = vec2DRadarOrigin.x;
-		vec2d.y = M_SQRT2 * m_radarRange + vec2DRadarOrigin.y;
-		TransformRealWorldPointToRadarSpace(in, vec2d);
-		LimitRadarPoint(in);
-		TransformRadarPointToScreenSpace(out, in);
-		DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255);
-
-		CEntity *blipEntity = nil;
-		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
-			if (!ms_RadarTrace[blipId].m_bInUse)
-				continue;
-
-			switch (ms_RadarTrace[blipId].m_eBlipType) {
-				case BLIP_CAR:
-				case BLIP_CHAR:
-				case BLIP_OBJECT:
-					if (ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SAVE
-						|| ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_WEAPON) {
-
-						switch (ms_RadarTrace[blipId].m_eBlipType) {
-							case BLIP_CAR:
-								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							case BLIP_CHAR:
-								blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								if (blipEntity != nil) {
-									if (((CPed*)blipEntity)->InVehicle())
-										blipEntity = ((CPed*)blipEntity)->m_pMyVehicle;
-								}
-								break;
-							case BLIP_OBJECT:
-								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							default:
-								break;
-						}
-						if (blipEntity) {
-							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-								if (CTheScripts::IsDebugOn()) {
-									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
-									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-										ms_RadarTrace[blipId].m_Radius = 5.0f;
-								}
-							}
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
-								float dist = LimitRadarPoint(in);
-								TransformRadarPointToScreenSpace(out, in);
-								if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE) {
-									DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-								} else {
-#ifdef TRIANGULAR_BLIPS
-									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-									CVector &blipPos = blipEntity->GetPosition();
-									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
-									if (blipPos.z - pos.z <= 2.0f) {
-										if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
-										else mode = BLIP_MODE_SQUARE;
-									}
-									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-#else
-									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-								}
-							}
-						}
-					}
-					break;
-				case BLIP_COORD:
-				case BLIP_CONTACT_POINT:
-					if ((ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SAVE
-						|| ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_WEAPON)
-						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
-
-						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-							if (CTheScripts::IsDebugOn()) {
-								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
-								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-									ms_RadarTrace[blipId].m_Radius = 5.0f;
-							}
-						}
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
-							float dist = LimitRadarPoint(in);
-							TransformRadarPointToScreenSpace(out, in);
-							if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE) {
-								DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-							} else {
-#ifdef TRIANGULAR_BLIPS
-								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
-								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
-								if (blipPos.z - pos.z <= 2.0f) {
-									if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
-									else mode = BLIP_MODE_SQUARE;
-								}
-								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-#else
-								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-							}
-						}
-					}
-					break;
-				default:
-					break;
-			}
-		}
-		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
-			if (!ms_RadarTrace[blipId].m_bInUse)
-				continue;
-
-			switch (ms_RadarTrace[blipId].m_eBlipType) {
-				case BLIP_CAR:
-				case BLIP_CHAR:
-				case BLIP_OBJECT:
-					if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SAVE
-						&& ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_WEAPON) {
-
-						switch (ms_RadarTrace[blipId].m_eBlipType) {
-							case BLIP_CAR:
-								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							case BLIP_CHAR:
-								blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								if (blipEntity != nil) {
-									if (((CPed*)blipEntity)->InVehicle())
-										blipEntity = ((CPed*)blipEntity)->m_pMyVehicle;
-								}
-								break;
-							case BLIP_OBJECT:
-								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							default:
-								break;
-						}
-
-						if (blipEntity) {
-							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-								if (CTheScripts::IsDebugOn()) {
-									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
-									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-										ms_RadarTrace[blipId].m_Radius = 5.0f;
-								}
-							}
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
-								float dist = LimitRadarPoint(in);
-								TransformRadarPointToScreenSpace(out, in);
-								if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE)
-									DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-								else
-#ifdef TRIANGULAR_BLIPS
-								{
-									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-									CVector &blipPos = blipEntity->GetPosition();
-									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
-									if (blipPos.z - pos.z <= 2.0f) {
-										if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
-										else mode = BLIP_MODE_SQUARE;
-									}
-									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-								}
-#else
-									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-							}
-						}
-					}
-					break;
-				default:
-					break;
-			}
-		}
-		for (int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
-			if (!ms_RadarTrace[blipId].m_bInUse)
-				continue;
-
-			switch (ms_RadarTrace[blipId].m_eBlipType) {
-				case BLIP_COORD:
-				case BLIP_CONTACT_POINT:
-					if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SAVE
-						&& ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_WEAPON
-						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
-
-						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-							if (CTheScripts::IsDebugOn()) {
-								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
-								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-									ms_RadarTrace[blipId].m_Radius = 5.0f;
-							}
-						}
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
-							float dist = LimitRadarPoint(in);
-							TransformRadarPointToScreenSpace(out, in);
-							if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE)
-								DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-							else
-#ifdef TRIANGULAR_BLIPS
-							{
-								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
-								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
-								if (blipPos.z - pos.z <= 2.0f) {
-									if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
-									else mode = BLIP_MODE_SQUARE;
-								}
-								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-							}
-#else
-								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-						}
-					}
-					break;
-				default:
-					break;
-			}
-		}
-	}
-}
-
-void CRadar::DrawMap()
-{
-	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
-		if (FindPlayerVehicle()) {
-			float speed = FindPlayerSpeed().Magnitude();
-			if (speed < RADAR_MIN_SPEED)
-				m_radarRange = RADAR_MIN_RANGE;
-			else if (speed < RADAR_MAX_SPEED)
-				m_radarRange = (speed - RADAR_MIN_SPEED)/(RADAR_MAX_SPEED-RADAR_MIN_SPEED) * (RADAR_MAX_RANGE-RADAR_MIN_RANGE) + RADAR_MIN_RANGE;
-			else
-				m_radarRange = RADAR_MAX_RANGE;
-		}
-		else
-			m_radarRange = RADAR_MIN_RANGE;
-
-		vec2DRadarOrigin = CVector2D(FindPlayerCentreOfWorld_NoSniperShift());
-		DrawRadarMap();
-	}
-}
-
-void CRadar::DrawRadarMap()
-{
-	// Game calculates an unused CRect here
-
-	DrawRadarMask();
-
-	// top left ist (0, 0)
-	int x = floorf((vec2DRadarOrigin.x - WORLD_MIN_X) / RADAR_TILE_SIZE);
-	int y = ceilf((RADAR_NUM_TILES - 1) - (vec2DRadarOrigin.y - WORLD_MIN_Y) / RADAR_TILE_SIZE);
-	StreamRadarSections(x, y);
-
-	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
-	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
-	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
-	RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE);
-
-	DrawRadarSection(x - 1, y - 1);
-	DrawRadarSection(x, y - 1);
-	DrawRadarSection(x + 1, y - 1);
-	DrawRadarSection(x - 1, y);
-	DrawRadarSection(x, y);
-	DrawRadarSection(x + 1, y);
-	DrawRadarSection(x - 1, y + 1);
-	DrawRadarSection(x, y + 1);
-	DrawRadarSection(x + 1, y + 1);
-}
-
-void CRadar::DrawRadarMask() 
-{ 
-	CVector2D corners[4] = {
-		CVector2D(1.0f, -1.0f),
-		CVector2D(1.0f, 1.0f),
-		CVector2D(-1.0f, 1.0f),
-		CVector2D(-1.0, -1.0f)
-	};
-
-	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
-	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
-	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
-	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
-	RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONALWAYS);
-
-	CVector2D out[8];
-	CVector2D in;
-
-	// Draw the shape we want to mask out from the radar in four segments
-	for (int i = 0; i < 4; i++) {
-		// First point is always the corner itself
-		in.x = corners[i].x;
-		in.y = corners[i].y;
-		TransformRadarPointToScreenSpace(out[0], in);
-
-		// Then generate a quarter of the circle
-		for (int j = 0; j < 7; j++) {
-			in.x = corners[i].x * Cos(j * (PI / 2.0f / 6.0f));
-			in.y = corners[i].y * Sin(j * (PI / 2.0f / 6.0f));
-			TransformRadarPointToScreenSpace(out[j + 1], in);
-		};
-
-		CSprite2d::SetMaskVertices(8, (float *)out);
-		RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8);
-	};
-
-	RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER);
-}
-
-void CRadar::DrawRadarSection(int32 x, int32 y)
-{
-	int i;
-	RwTexDictionary *txd;
-	CVector2D worldPoly[8];
-	CVector2D radarCorners[4];
-	CVector2D radarPoly[8];
-	CVector2D texCoords[8];
-	CVector2D screenPoly[8];
-	int numVertices;
-	RwTexture *texture = nil;
-
-	GetTextureCorners(x, y, worldPoly);
-	ClipRadarTileCoords(x, y);
-
-	assert(CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y]));
-	txd = CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])->texDict;
-	if (txd)
-		texture = GetFirstTexture(txd);
-	if (texture == nil)
-		return;
-
-	for (i = 0; i < 4; i++)
-		TransformRealWorldPointToRadarSpace(radarCorners[i], worldPoly[i]);
-
-	numVertices = ClipRadarPoly(radarPoly, radarCorners);
-
-	// FIX: can return earlier here
-//	if(numVertices == 0)
-	if (numVertices < 3)
-		return;
-
-	for (i = 0; i < numVertices; i++) {
-		TransformRadarPointToRealWorldSpace(worldPoly[i], radarPoly[i]);
-		TransformRealWorldToTexCoordSpace(texCoords[i], worldPoly[i], x, y);
-		TransformRadarPointToScreenSpace(screenPoly[i], radarPoly[i]);
-	}
-	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(texture));
-	CSprite2d::SetVertices(numVertices, (float*)screenPoly, (float*)texCoords, CRGBA(255, 255, 255, 255));
-	// check done above now
-//	if(numVertices > 2)
-	RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices);
-}
-
-void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha)
-{
-	RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
-}
-
-void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha)
-{
-	CVector curPosn[4];
-	CVector oldPosn[4];
-
-	curPosn[0].x = x - SCREEN_SCALE_X(5.6f);
-	curPosn[0].y = y + SCREEN_SCALE_Y(5.6f);
-
-	curPosn[1].x = x + SCREEN_SCALE_X(5.6f);
-	curPosn[1].y = y + SCREEN_SCALE_Y(5.6f);
-
-	curPosn[2].x = x - SCREEN_SCALE_X(5.6f);
-	curPosn[2].y = y - SCREEN_SCALE_Y(5.6f);
-
-	curPosn[3].x = x + SCREEN_SCALE_X(5.6f);
-	curPosn[3].y = y - SCREEN_SCALE_Y(5.6f);
-
-	for (uint32 i = 0; i < 4; i++) {
-		oldPosn[i] = curPosn[i];
-
-		curPosn[i].x = x + (oldPosn[i].x - x) * Cos(angle) + (oldPosn[i].y - y) * Sin(angle);
-		curPosn[i].y = y - (oldPosn[i].x - x) * Sin(angle) + (oldPosn[i].y - y) * Cos(angle);
-	}
-
-	sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
-}
-
-int32 CRadar::GetActualBlipArrayIndex(int32 i)
-{
-	if (i == -1)
-		return -1;
-	else if ((i & 0xFFFF0000) >> 16 != ms_RadarTrace[(uint16)i].m_BlipIndex)
-		return -1;
-	else
-		return (uint16)i;
-}
-
-int32 CRadar::GetNewUniqueBlipIndex(int32 i)
-{
-	if (ms_RadarTrace[i].m_BlipIndex >= UINT16_MAX - 1)
-		ms_RadarTrace[i].m_BlipIndex = 1;
-	else
-		ms_RadarTrace[i].m_BlipIndex++;
-	return i | (ms_RadarTrace[i].m_BlipIndex << 16);
-}
-
-uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright)
-{
-	int32 c;
-	switch (color) {
-	case 0:
-		if (bright)
-			c = 0x712B49FF;
-		else
-			c = 0x7F0000FF;
-		break;
-	case 1:
-		if (bright)
-			c = 0x5FA06AFF;
-		else
-			c = 0x007F00FF;
-		break;
-	case 2:
-		if (bright)
-			c = 0x80A7F3FF;
-		else
-			c = 0x00007FFF;
-		break;
-	case 3:
-		if (bright)
-			c = 0xE1E1E1FF;
-		else
-			c = 0x7F7F7FFF;
-		break;
-	case 4:
-		if (bright)
-			c = 0xFFFF00FF;
-		else
-			c = 0x7F7F00FF;
-		break;
-	case 5:
-		if (bright)
-			c = 0xFF00FFFF;
-		else
-			c = 0x7F007FFF;
-		break;
-	case 6:
-		if (bright)
-			c = 0x00FFFFFF;
-		else
-			c = 0x007F7FFF;
-		break;
-	default:
-		c = color;
-		break;
-	};
-	return c;
-}
-
-const char* gRadarTexNames[] = {
-	"radar00", "radar01", "radar02", "radar03", "radar04", "radar05", "radar06", "radar07",
-	"radar08", "radar09", "radar10", "radar11", "radar12", "radar13", "radar14", "radar15",
-	"radar16", "radar17", "radar18", "radar19", "radar20", "radar21", "radar22", "radar23",
-	"radar24", "radar25", "radar26", "radar27", "radar28", "radar29", "radar30", "radar31",
-	"radar32", "radar33", "radar34", "radar35", "radar36", "radar37", "radar38", "radar39",
-	"radar40", "radar41", "radar42", "radar43", "radar44", "radar45", "radar46", "radar47",
-	"radar48", "radar49", "radar50", "radar51", "radar52", "radar53", "radar54", "radar55",
-	"radar56", "radar57", "radar58", "radar59", "radar60", "radar61", "radar62", "radar63",
-};
-
-void
-CRadar::Initialise()
-{
-	for (int i = 0; i < NUMRADARBLIPS; i++) {
-		ms_RadarTrace[i].m_BlipIndex = 1;
-		SetRadarMarkerState(i, false);
-		ms_RadarTrace[i].m_bInUse = false;
-		ms_RadarTrace[i].m_eBlipType = BLIP_NONE;
-		ms_RadarTrace[i].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
-		ms_RadarTrace[i].m_IconID = RADAR_SPRITE_NONE;
-	}
-
-	m_radarRange = 350.0f;
-	for (int i = 0; i < 64; i++) 
-		gRadarTxdIds[i] = CTxdStore::FindTxdSlot(gRadarTexNames[i]);
-}
-
-float CRadar::LimitRadarPoint(CVector2D &point)
-{
-	float dist, invdist;
-
-	dist = point.Magnitude();
-	if (dist > 1.0f) {
-		invdist = 1.0f / dist;
-		point.x *= invdist;
-		point.y *= invdist;
-	}
-	return dist;
-}
-
-void CRadar::LoadAllRadarBlips(uint8 *buf, uint32 size)
-{
-	Initialise();
-INITSAVEBUF
-	CheckSaveHeader(buf, 'R', 'D', 'R', '\0', size - SAVE_HEADER_SIZE);
-
-	for (int i = 0; i < NUMRADARBLIPS; i++)
-		ms_RadarTrace[i] = ReadSaveBuf<CBlip>(buf);
-
-VALIDATESAVEBUF(size);
-}
-
-void
-CRadar::LoadTextures()
-{
-	CTxdStore::PushCurrentTxd();
-	CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("hud"));
-	AsukaSprite.SetTexture("radar_asuka");
-	BombSprite.SetTexture("radar_bomb");
-	CatSprite.SetTexture("radar_cat");
-	CentreSprite.SetTexture("radar_centre");
-	CopcarSprite.SetTexture("radar_copcar");
-	DonSprite.SetTexture("radar_don");
-	EightSprite.SetTexture("radar_eight");
-	ElSprite.SetTexture("radar_el");
-	IceSprite.SetTexture("radar_ice");
-	JoeySprite.SetTexture("radar_joey");
-	KenjiSprite.SetTexture("radar_kenji");
-	LizSprite.SetTexture("radar_liz");
-	LuigiSprite.SetTexture("radar_luigi");
-	NorthSprite.SetTexture("radar_north");
-	RaySprite.SetTexture("radar_ray");
-	SalSprite.SetTexture("radar_sal");
-	SaveSprite.SetTexture("radar_save");
-	SpraySprite.SetTexture("radar_spray");
-	TonySprite.SetTexture("radar_tony");
-	WeaponSprite.SetTexture("radar_weapon");
-	CTxdStore::PopCurrentTxd();
-}
-
-void RemoveMapSection(int32 x, int32 y)
-{
-	if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
-		CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]);
-}
-
-void CRadar::RemoveRadarSections()
-{
-	for (int i = 0; i < 8; i++)
-		for (int j = 0; j < 8; j++)
-			RemoveMapSection(i, j);
-}
-
-void CRadar::RequestMapSection(int32 x, int32 y)
-{
-	ClipRadarTileCoords(x, y);
-	CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
-}
-
-void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size)
-{
-	*size = SAVE_HEADER_SIZE + sizeof(ms_RadarTrace);
-INITSAVEBUF
-	WriteSaveHeader(buf, 'R', 'D', 'R', '\0', *size - SAVE_HEADER_SIZE);
-
-	for (int i = 0; i < NUMRADARBLIPS; i++)
-		WriteSaveBuf(buf, ms_RadarTrace[i]);
-
-VALIDATESAVEBUF(*size);
-}
-
-void CRadar::SetBlipSprite(int32 i, int32 icon)
-{
-	int index = CRadar::GetActualBlipArrayIndex(i);
-	if (index != -1) {
-		ms_RadarTrace[index].m_IconID = icon;
-	}
-}
-
-int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay display)
-{
-	int nextBlip;
-	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
-		if (!ms_RadarTrace[nextBlip].m_bInUse)
-			break;
-	}
-	ms_RadarTrace[nextBlip].m_eBlipType = type;
-	ms_RadarTrace[nextBlip].m_nColor = color;
-	ms_RadarTrace[nextBlip].m_bDim = 1;
-	ms_RadarTrace[nextBlip].m_bInUse = 1;
-	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
-	ms_RadarTrace[nextBlip].m_vec2DPos = pos;
-	ms_RadarTrace[nextBlip].m_vecPos = pos;
-	ms_RadarTrace[nextBlip].m_nEntityHandle = 0;
-	ms_RadarTrace[nextBlip].m_wScale = 1;
-	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
-	ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
-	return CRadar::GetNewUniqueBlipIndex(nextBlip);
-}
-
-int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDisplay display)
-{
-	int nextBlip;
-	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
-		if (!ms_RadarTrace[nextBlip].m_bInUse)
-			break;
-	}
-	ms_RadarTrace[nextBlip].m_eBlipType = type;
-	ms_RadarTrace[nextBlip].m_nColor = color;
-	ms_RadarTrace[nextBlip].m_bDim = 1;
-	ms_RadarTrace[nextBlip].m_bInUse = 1;
-	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
-	ms_RadarTrace[nextBlip].m_nEntityHandle = handle;
-	ms_RadarTrace[nextBlip].m_wScale = 1;
-	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
-	ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
-	return GetNewUniqueBlipIndex(nextBlip);
-}
-
-void CRadar::SetRadarMarkerState(int32 counter, bool flag)
-{
-	CEntity *e;
-	switch (ms_RadarTrace[counter].m_eBlipType) {
-	case BLIP_CAR:
-		e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
-		break;
-	case BLIP_CHAR:
-		e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
-		break;
-	case BLIP_OBJECT:
-		e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
-		break;
-	default:
-		return;
-	}
-
-	if (e)
-		e->bHasBlip = flag;
-}
-
-void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) {
-	float f1 = radius * 1.4f;
-	float f2 = radius * 0.5f;
-	CVector p1, p2;
-
-	p1 = pos + TheCamera.GetUp()*f1;
-	p2 = pos + TheCamera.GetUp()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-
-	p1 = pos - TheCamera.GetUp()*f1;
-	p2 = pos - TheCamera.GetUp()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-
-	p1 = pos + TheCamera.GetRight()*f1;
-	p2 = pos + TheCamera.GetRight()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-
-	p1 = pos - TheCamera.GetRight()*f1;
-	p2 = pos - TheCamera.GetRight()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-}
-
-void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha)
-{
-	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
-		return;
-
-	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
-	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
-}
-
-void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint8 mode)
-{
-	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
-		return;
-
-	switch (mode)
-	{
-	case BLIP_MODE_TRIANGULAR_UP:
-		// size++; // VC does size + 1 for triangles
-		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 3.0f), y + SCREEN_SCALE_Y(size + 2.0f), x - (SCREEN_SCALE_X(size + 3.0f)), y + SCREEN_SCALE_Y(size + 2.0f), x, y - (SCREEN_SCALE_Y(size + 3.0f)), x, y - (SCREEN_SCALE_Y(size + 3.0f)), CRGBA(0, 0, 0, alpha));
-		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 1.0f), y + SCREEN_SCALE_Y(size + 1.0f), x - (SCREEN_SCALE_X(size + 1.0f)), y + SCREEN_SCALE_Y(size + 1.0f), x, y - (SCREEN_SCALE_Y(size + 1.0f)), x, y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
-		break;
-	case BLIP_MODE_TRIANGULAR_DOWN:
-		// size++; // VC does size + 1 for triangles
-		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 2.0f), x, y + SCREEN_SCALE_Y(size + 3.0f), x + SCREEN_SCALE_X(size + 3.0f), y - (SCREEN_SCALE_Y(size + 2.0f)), x - (SCREEN_SCALE_X(size + 3.0f)), y - (SCREEN_SCALE_Y(size + 2.0f)), CRGBA(0, 0, 0, alpha));
-		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 1.0f), x, y + SCREEN_SCALE_Y(size + 1.0f), x + SCREEN_SCALE_X(size + 1.0f), y - (SCREEN_SCALE_Y(size + 1.0f)), x - (SCREEN_SCALE_X(size + 1.0f)), y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
-		break;
-	case BLIP_MODE_SQUARE:
-		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
-		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
-		break;
-	}
-}
-
-void CRadar::Shutdown()
-{
-	AsukaSprite.Delete();
-	BombSprite.Delete();
-	CatSprite.Delete();
-	CentreSprite.Delete();
-	CopcarSprite.Delete();
-	DonSprite.Delete();
-	EightSprite.Delete();
-	ElSprite.Delete();
-	IceSprite.Delete();
-	JoeySprite.Delete();
-	KenjiSprite.Delete();
-	LizSprite.Delete();
-	LuigiSprite.Delete();
-	NorthSprite.Delete();
-	RaySprite.Delete();
-	SalSprite.Delete();
-	SaveSprite.Delete();
-	SpraySprite.Delete();
-	TonySprite.Delete();
-	WeaponSprite.Delete();
-	RemoveRadarSections();
-}
-
-void CRadar::StreamRadarSections(const CVector &posn)
-{
-	StreamRadarSections(floorf((2000.0f + posn.x) / 500.0f), ceilf(7.0f - (2000.0f + posn.y) / 500.0f));
-}
-
-void CRadar::StreamRadarSections(int32 x, int32 y)
-{
-	for (int i = 0; i < RADAR_NUM_TILES; ++i) {
-		for (int j = 0; j < RADAR_NUM_TILES; ++j) {
-			if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1))
-				RequestMapSection(i, j);
-			else
-				RemoveMapSection(i, j);
-		};
-	};
-}
-
-void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y)
-{
-	out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X);
-	out.y = -(in.y - ((RADAR_NUM_TILES - y) * RADAR_TILE_SIZE + WORLD_MIN_Y));
-	out.x /= RADAR_TILE_SIZE;
-	out.y /= RADAR_TILE_SIZE;
-}
-
-void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
-{
-	float s, c;
-
-	s = -Sin(TheCamera.GetForward().Heading());
-	c = Cos(TheCamera.GetForward().Heading());
-
-	if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) {
-		s = 0.0f;
-		c = 1.0f;
-	}
-	else if (TheCamera.GetLookDirection() != LOOKING_FORWARD) {
-		CVector forward;
-
-		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) {
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
-			forward.Normalise();	// a bit useless...
-		}
-		else
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
-
-		s = -Sin(forward.Heading());
-		c = Cos(forward.Heading());
-	}
-
-	out.x = s * in.y + c * in.x;
-	out.y = c * in.y - s * in.x;
-
-	out = out * m_radarRange + vec2DRadarOrigin;
-}
-
-// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0)
-void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in)
-{
-#ifdef FIX_BUGS
-	out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT);
-#else
-	out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT;
-#endif
-	out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT);
-}
-
-void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
-{
-	float s, c;
-	if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) {
-		s = 0.0f;
-		c = 1.0f;
-	}
-	else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) {
-		s = Sin(TheCamera.GetForward().Heading());
-		c = Cos(TheCamera.GetForward().Heading());
-	}
-	else {
-		CVector forward;
-
-		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) {
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
-			forward.Normalise();	// a bit useless...
-		}
-		else
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
-
-		s = Sin(forward.Heading());
-		c = Cos(forward.Heading());
-	}
-
-	float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_radarRange);
-	float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_radarRange);
-
-	out.x = s * y + c * x;
-	out.y = c * y - s * x;
-}
-
-// Transform from section indices to world coordinates
-void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out)
-{
-	x =   x - RADAR_NUM_TILES/2;
-	y = -(y - RADAR_NUM_TILES/2);
-
-	// bottom left
-	out[0].x = RADAR_TILE_SIZE * (x);
-	out[0].y = RADAR_TILE_SIZE * (y - 1);
-
-	// bottom right
-	out[1].x = RADAR_TILE_SIZE * (x + 1);
-	out[1].y = RADAR_TILE_SIZE * (y - 1);
-
-	// top right
-	out[2].x = RADAR_TILE_SIZE * (x + 1);
-	out[2].y = RADAR_TILE_SIZE * (y);
-
-	// top left
-	out[3].x = RADAR_TILE_SIZE * (x);
-	out[3].y = RADAR_TILE_SIZE * (y);
-}
-
-void CRadar::ClipRadarTileCoords(int32 &x, int32 &y)
-{
-	if (x < 0)
-		x = 0;
-	if (x > RADAR_NUM_TILES-1)
-		x = RADAR_NUM_TILES-1;
-	if (y < 0)
-		y = 0;
-	if (y > RADAR_NUM_TILES-1)
-		y = RADAR_NUM_TILES-1;
-}
-
-
-bool CRadar::IsPointInsideRadar(const CVector2D &point)
-{
-	if (point.x < -1.0f || point.x > 1.0f) return false;
-	if (point.y < -1.0f || point.y > 1.0f) return false;
-	return true;
-}
-
-// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1
-int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2)
-{
-	float d1, d2;
-	float t;
-	float x, y;
-	float shortest = 1.0f;
-	int edge = -1;
-
-	// clip against left edge, x = -1.0
-	d1 = -1.0f - p1.x;
-	d2 = -1.0f - p2.x;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		y = (p2.y - p1.y)*t + p1.y;
-		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
-			out.x = -1.0f;
-			out.y = y;
-			edge = 3;
-			shortest = t;
-		}
-	}
-
-	// clip against right edge, x = 1.0
-	d1 = p1.x - 1.0f;
-	d2 = p2.x - 1.0f;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		y = (p2.y - p1.y)*t + p1.y;
-		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
-			out.x = 1.0f;
-			out.y = y;
-			edge = 1;
-			shortest = t;
-		}
-	}
-
-	// clip against top edge, y = -1.0
-	d1 = -1.0f - p1.y;
-	d2 = -1.0f - p2.y;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		x = (p2.x - p1.x)*t + p1.x;
-		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
-			out.y = -1.0f;
-			out.x = x;
-			edge = 0;
-			shortest = t;
-		}
-	}
-
-	// clip against bottom edge, y = 1.0
-	d1 = p1.y - 1.0f;
-	d2 = p2.y - 1.0f;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		x = (p2.x - p1.x)*t + p1.x;
-		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
-			out.y = 1.0f;
-			out.x = x;
-			edge = 2;
-			shortest = t;
-		}
-	}
-
-	return edge;
-}
-
-STARTPATCHES
-	InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP);
-	InjectHook(0x4A3F60, CRadar::Shutdown, PATCH_JUMP);
-	InjectHook(0x4A4030, CRadar::LoadTextures, PATCH_JUMP);
-	InjectHook(0x4A4180, CRadar::GetNewUniqueBlipIndex, PATCH_JUMP);
-	InjectHook(0x4A41C0, CRadar::GetActualBlipArrayIndex, PATCH_JUMP);
-	InjectHook(0x4A4200, CRadar::DrawMap, PATCH_JUMP);
-	InjectHook(0x4A42F0, CRadar::DrawBlips, PATCH_JUMP);
-	InjectHook(0x4A4C70, CRadar::Draw3dMarkers, PATCH_JUMP);
-	InjectHook(0x4A4F30, CRadar::LimitRadarPoint, PATCH_JUMP);
-	InjectHook(0x4A4F90, CRadar::CalculateBlipAlpha, PATCH_JUMP);
-	InjectHook(0x4A5040, CRadar::TransformRadarPointToScreenSpace, PATCH_JUMP);
-	InjectHook(0x4A50D0, CRadar::TransformRealWorldPointToRadarSpace, PATCH_JUMP);
-	InjectHook(0x4A5300, CRadar::TransformRadarPointToRealWorldSpace, PATCH_JUMP);
-	InjectHook(0x4A5530, CRadar::TransformRealWorldToTexCoordSpace, PATCH_JUMP);
-	InjectHook(0x4A5590, CRadar::SetCoordBlip, PATCH_JUMP);
-	InjectHook(0x4A5640, CRadar::SetEntityBlip, PATCH_JUMP);
-	InjectHook(0x4A56C0, CRadar::ClearBlipForEntity, PATCH_JUMP);
-	InjectHook(0x4A5720, CRadar::ClearBlip, PATCH_JUMP);
-	InjectHook(0x4A5770, CRadar::ChangeBlipColour, PATCH_JUMP);
-	InjectHook(0x4A57A0, CRadar::ChangeBlipBrightness, PATCH_JUMP);
-	InjectHook(0x4A57E0, CRadar::ChangeBlipScale, PATCH_JUMP);
-	InjectHook(0x4A5810, CRadar::ChangeBlipDisplay, PATCH_JUMP);
-	InjectHook(0x4A5840, CRadar::SetBlipSprite, PATCH_JUMP);
-	InjectHook(0x4A5870, CRadar::ShowRadarTrace, PATCH_JUMP);
-	InjectHook(0x4A59C0, CRadar::ShowRadarMarker, PATCH_JUMP);
-	InjectHook(0x4A5BB0, CRadar::GetRadarTraceColour, PATCH_JUMP);
-	InjectHook(0x4A5C60, CRadar::SetRadarMarkerState, PATCH_JUMP);
-	InjectHook(0x4A5D10, CRadar::DrawRotatingRadarSprite, PATCH_JUMP);
-	InjectHook(0x4A5EF0, CRadar::DrawRadarSprite, PATCH_JUMP);
-	InjectHook(0x4A60E0, CRadar::RemoveRadarSections, PATCH_JUMP);
-	InjectHook(0x4A6100, (void (*)(int32, int32))&CRadar::StreamRadarSections, PATCH_JUMP);
-	InjectHook(0x4A64A0, CRadar::ClipRadarPoly, PATCH_JUMP);
-	InjectHook(0x4A67E0, CRadar::DrawRadarSection, PATCH_JUMP);
-	InjectHook(0x4A69C0, CRadar::DrawRadarMask, PATCH_JUMP);
-	InjectHook(0x4A6B60, (void (*)(const CVector&))&CRadar::StreamRadarSections, PATCH_JUMP);
-	InjectHook(0x4A6C20, CRadar::DrawRadarMap, PATCH_JUMP);
-	InjectHook(0x4A6E30, CRadar::SaveAllRadarBlips, PATCH_JUMP);
-	InjectHook(0x4A6F30, CRadar::LoadAllRadarBlips, PATCH_JUMP);
-
-	InjectHook(0x4A61C0, CRadar::GetTextureCorners, PATCH_JUMP);
-	InjectHook(0x4A6160, CRadar::IsPointInsideRadar, PATCH_JUMP);
-	InjectHook(0x4A6250, CRadar::LineRadarBoxCollision, PATCH_JUMP);
-ENDPATCHES
+#include "config.h"
+#include "common.h"
+#include "patcher.h"
+#include "RwHelper.h"
+#include "Radar.h"
+#include "Camera.h"
+#include "Hud.h"
+#include "World.h"
+#include "Frontend.h"
+#include "General.h"
+#include "Vehicle.h"
+#include "Pools.h"
+#include "Script.h"
+#include "TxdStore.h"
+#include "World.h"
+#include "Streaming.h"
+#include "SpecialFX.h"
+
+float &CRadar::m_radarRange = *(float*)0x8E281C;
+sRadarTrace (&CRadar::ms_RadarTrace)[NUMRADARBLIPS] = *(sRadarTrace(*)[NUMRADARBLIPS]) * (uintptr*)0x6ED5E0;
+CVector2D &vec2DRadarOrigin = *(CVector2D*)0x6299B8;
+int32 gRadarTxdIds[64];// = (int*)0x6299C0;
+
+CSprite2d CRadar::AsukaSprite;// = *(CSprite2d*)0x8F1A40;
+CSprite2d CRadar::BombSprite;// = (CSprite2d*)0x8F5FB4;
+CSprite2d CRadar::CatSprite;// = (CSprite2d*)0x885B24;
+CSprite2d CRadar::CentreSprite;// = (CSprite2d*)0x8F6268;
+CSprite2d CRadar::CopcarSprite;// = (CSprite2d*)0x8F1A2C;
+CSprite2d CRadar::DonSprite;// = (CSprite2d*)0x8F2BE0;
+CSprite2d CRadar::EightSprite;// = (CSprite2d*)0x8F2BCC;
+CSprite2d CRadar::ElSprite;// = (CSprite2d*)0x8F1B80;
+CSprite2d CRadar::IceSprite;// = (CSprite2d*)0x9415FC;
+CSprite2d CRadar::JoeySprite;// = (CSprite2d*)0x8F2C00;
+CSprite2d CRadar::KenjiSprite;// = (CSprite2d*)0x8F2C68;
+CSprite2d CRadar::LizSprite;// = (CSprite2d*)0x8F5830;
+CSprite2d CRadar::LuigiSprite;// = (CSprite2d*)0x8F1A3C;
+CSprite2d CRadar::NorthSprite;// = (CSprite2d*)0x8F6274;
+CSprite2d CRadar::RaySprite;// = (CSprite2d*)0x8E2A7C;
+CSprite2d CRadar::SalSprite;// = (CSprite2d*)0x8F29EC;
+CSprite2d CRadar::SaveSprite;// = (CSprite2d*)0x8F5F74;
+CSprite2d CRadar::SpraySprite;// = (CSprite2d*)0x94307C;
+CSprite2d CRadar::TonySprite;// = (CSprite2d*)0x885B58;
+CSprite2d CRadar::WeaponSprite;// = (CSprite2d*)0x941534;
+
+CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { 
+	nil,
+	&AsukaSprite,
+	&BombSprite,
+	&CatSprite,
+	&CentreSprite,
+	&CopcarSprite,
+	&DonSprite,
+	&EightSprite,
+	&ElSprite,
+	&IceSprite,
+	&JoeySprite,
+	&KenjiSprite,
+	&LizSprite,
+	&LuigiSprite,
+	&NorthSprite,
+	&RaySprite,
+	&SalSprite,
+	&SaveSprite,
+	&SpraySprite,
+	&TonySprite,
+	&WeaponSprite
+};
+
+#define RADAR_NUM_TILES (8)
+#define RADAR_TILE_SIZE (WORLD_SIZE_X / RADAR_NUM_TILES)
+static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square");
+
+#define RADAR_MIN_RANGE (120.0f)
+#define RADAR_MAX_RANGE (350.0f)
+#define RADAR_MIN_SPEED (0.3f)
+#define RADAR_MAX_SPEED (0.9f)
+
+#ifdef MENU_MAP
+CRGBA CRadar::ArrowBlipColour1;
+CRGBA CRadar::ArrowBlipColour2;
+uint16 CRadar::MapLegendCounter;
+uint16 CRadar::MapLegendList[NUM_MAP_LEGENDS];
+int CRadar::TargetMarkerId = -1;
+#endif
+
+// taken from VC
+float CRadar::cachedCos;
+float CRadar::cachedSin;
+
+void ClipRadarTileCoords(int32 &x, int32 &y)
+{
+	if (x < 0)
+		x = 0;
+	if (x > RADAR_NUM_TILES-1)
+		x = RADAR_NUM_TILES-1;
+	if (y < 0)
+		y = 0;
+	if (y > RADAR_NUM_TILES-1)
+		y = RADAR_NUM_TILES-1;
+}
+
+void RequestMapSection(int32 x, int32 y)
+{
+	ClipRadarTileCoords(x, y);
+	CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
+}
+
+void RemoveMapSection(int32 x, int32 y)
+{
+	if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
+		CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]);
+}
+
+// Transform from section indices to world coordinates
+void GetTextureCorners(int32 x, int32 y, CVector2D *out)
+{
+	x =   x - RADAR_NUM_TILES/2;
+	y = -(y - RADAR_NUM_TILES/2);
+
+	// bottom left
+	out[0].x = RADAR_TILE_SIZE * (x);
+	out[0].y = RADAR_TILE_SIZE * (y - 1);
+
+	// bottom right
+	out[1].x = RADAR_TILE_SIZE * (x + 1);
+	out[1].y = RADAR_TILE_SIZE * (y - 1);
+
+	// top right
+	out[2].x = RADAR_TILE_SIZE * (x + 1);
+	out[2].y = RADAR_TILE_SIZE * (y);
+
+	// top left
+	out[3].x = RADAR_TILE_SIZE * (x);
+	out[3].y = RADAR_TILE_SIZE * (y);
+}
+
+
+bool IsPointInsideRadar(const CVector2D &point)
+{
+	if (point.x < -1.0f || point.x > 1.0f) return false;
+	if (point.y < -1.0f || point.y > 1.0f) return false;
+	return true;
+}
+
+// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1
+int LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2)
+{
+	float d1, d2;
+	float t;
+	float x, y;
+	float shortest = 1.0f;
+	int edge = -1;
+
+	// clip against left edge, x = -1.0
+	d1 = -1.0f - p1.x;
+	d2 = -1.0f - p2.x;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		y = (p2.y - p1.y)*t + p1.y;
+		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
+			out.x = -1.0f;
+			out.y = y;
+			edge = 3;
+			shortest = t;
+		}
+	}
+
+	// clip against right edge, x = 1.0
+	d1 = p1.x - 1.0f;
+	d2 = p2.x - 1.0f;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		y = (p2.y - p1.y)*t + p1.y;
+		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
+			out.x = 1.0f;
+			out.y = y;
+			edge = 1;
+			shortest = t;
+		}
+	}
+
+	// clip against top edge, y = -1.0
+	d1 = -1.0f - p1.y;
+	d2 = -1.0f - p2.y;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		x = (p2.x - p1.x)*t + p1.x;
+		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
+			out.y = -1.0f;
+			out.x = x;
+			edge = 0;
+			shortest = t;
+		}
+	}
+
+	// clip against bottom edge, y = 1.0
+	d1 = p1.y - 1.0f;
+	d2 = p2.y - 1.0f;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		x = (p2.x - p1.x)*t + p1.x;
+		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
+			out.y = 1.0f;
+			out.x = x;
+			edge = 2;
+			shortest = t;
+		}
+	}
+
+	return edge;
+}
+
+
+uint8 CRadar::CalculateBlipAlpha(float dist)
+{
+#ifdef MENU_MAP
+	if (CMenuManager::bMenuMapActive)
+		return 255;
+#endif
+	if (dist <= 1.0f)
+		return 255;
+
+	if (dist <= 5.0f)
+		return (128.0f * ((dist - 1.0f) / 4.0f)) + ((1.0f - (dist - 1.0f) / 4.0f) * 255.0f);
+
+	return 128;
+}
+
+void CRadar::ChangeBlipBrightness(int32 i, int32 bright)
+{
+	int index = GetActualBlipArrayIndex(i);
+	if (index != -1)
+		ms_RadarTrace[index].m_bDim = bright != 1;
+}
+
+void CRadar::ChangeBlipColour(int32 i, int32 color)
+{
+	int index = GetActualBlipArrayIndex(i);
+	if (index != -1)
+		ms_RadarTrace[index].m_nColor = color;
+}
+
+void CRadar::ChangeBlipDisplay(int32 i, eBlipDisplay display)
+{
+	int index = GetActualBlipArrayIndex(i);
+	if (index != -1)
+		ms_RadarTrace[index].m_eBlipDisplay = display;
+}
+
+void CRadar::ChangeBlipScale(int32 i, int32 scale)
+{
+	int index = GetActualBlipArrayIndex(i);
+	if (index != -1)
+		ms_RadarTrace[index].m_wScale = scale;
+}
+
+void CRadar::ClearBlip(int32 i)
+{
+	int index = GetActualBlipArrayIndex(i);
+	if (index != -1) {
+		SetRadarMarkerState(index, false);
+		ms_RadarTrace[index].m_bInUse = false;
+#ifndef MENU_MAP
+		// Ssshhh
+		ms_RadarTrace[index].m_eBlipType = BLIP_NONE;
+		ms_RadarTrace[index].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
+		ms_RadarTrace[index].m_eRadarSprite = RADAR_SPRITE_NONE;
+#endif
+	}
+}
+
+void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
+{
+	for (int i = 0; i < NUMRADARBLIPS; i++) {
+		if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) {
+			SetRadarMarkerState(i, false);
+			ms_RadarTrace[i].m_bInUse = false;
+			ms_RadarTrace[i].m_eBlipType = BLIP_NONE;
+			ms_RadarTrace[i].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
+			ms_RadarTrace[i].m_eRadarSprite = RADAR_SPRITE_NONE;
+		}
+	};
+}
+
+// Why not a proper clipping algorithm?
+int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
+{
+	CVector2D corners[4] = {
+		{  1.0f, -1.0f },	// top right
+		{  1.0f,  1.0f },	// bottom right
+		{ -1.0f,  1.0f },	// bottom left
+		{ -1.0f, -1.0f },	// top left
+	};
+	CVector2D tmp;
+	int i, j, n;
+	int laste, e, e1, e2;;
+	bool inside[4];
+
+	for (i = 0; i < 4; i++)
+		inside[i] = IsPointInsideRadar(rect[i]);
+
+	laste = -1;
+	n = 0;
+	for (i = 0; i < 4; i++)
+		if (inside[i]) {
+			// point is inside, just add
+			poly[n++] = rect[i];
+		}
+		else {
+			// point is outside but line to this point might be clipped
+			e1 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 4 - 1) % 4]);
+			if (e1 != -1) {
+				laste = e1;
+				n++;
+			}
+			// and line from this point might be clipped as well
+			e2 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 1) % 4]);
+			if (e2 != -1) {
+				if (e1 == -1) {
+					// if other line wasn't clipped, i.e. it was complete outside,
+					// we may have to insert another vertex if last clipped line
+					// was on a different edge
+
+					// find the last intersection if we haven't seen it yet
+					if (laste == -1)
+						for (j = 3; j >= i; j--) {
+							// game uses an if here for j == 0
+							e = LineRadarBoxCollision(tmp, rect[j], rect[(j + 4 - 1) % 4]);
+							if (e != -1) {
+								laste = e;
+								break;
+							}
+						}
+					assert(laste != -1);
+
+					// insert corners that were skipped
+					tmp = poly[n];
+					for (e = laste; e != e2; e = (e + 1) % 4)
+						poly[n++] = corners[e];
+					poly[n] = tmp;
+				}
+				n++;
+			}
+		}
+
+	if (n == 0) {
+		// If no points, either the rectangle is completely outside or completely surrounds the radar
+		// no idea what's going on here...
+		float m = (rect[0].y - rect[1].y) / (rect[0].x - rect[1].x);
+		if ((m*rect[3].x - rect[3].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
+			m = (rect[0].y - rect[3].y) / (rect[0].x - rect[3].x);
+			if ((m*rect[1].x - rect[1].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
+				poly[0] = corners[0];
+				poly[1] = corners[1];
+				poly[2] = corners[2];
+				poly[3] = corners[3];
+				n = 4;
+			}
+		}
+	}
+
+	return n;
+}
+
+bool CRadar::DisplayThisBlip(int32 counter)
+{
+	switch (ms_RadarTrace[counter].m_eRadarSprite) {
+	case RADAR_SPRITE_BOMB:
+	case RADAR_SPRITE_SPRAY:
+	case RADAR_SPRITE_WEAPON:
+		return true;
+	default:
+		return false;
+	}
+}
+
+void CRadar::Draw3dMarkers()
+{
+	for (int i = 0; i < NUMRADARBLIPS; i++) {
+		if (ms_RadarTrace[i].m_bInUse) {
+			switch (ms_RadarTrace[i].m_eBlipType) {
+			case BLIP_CAR:
+			{
+				CEntity *entity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[i].m_nEntityHandle);
+				if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+					CVector pos = entity->GetPosition();
+					pos.z += 1.2f * CModelInfo::GetModelInfo(entity->GetModelIndex())->GetColModel()->boundingBox.max.z + 2.5f;
+					C3dMarkers::PlaceMarker(i | (ms_RadarTrace[i].m_BlipIndex << 16), 1, pos, 2.5f, 0, 128, 255, 255, 1024, 0.2f, 5);
+				}
+				break;
+			}
+			case BLIP_CHAR:
+			{
+				CEntity *entity = CPools::GetPedPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle);
+				if (entity != nil) {
+					if (((CPed*)entity)->InVehicle())
+						entity = ((CPed * )entity)->m_pMyVehicle;
+				}
+				if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+					CVector pos = entity->GetPosition();
+					pos.z += 3.0f;
+					C3dMarkers::PlaceMarker(i | (ms_RadarTrace[i].m_BlipIndex << 16), 1, pos, 1.5f, 0, 128, 255, 255, 1024, 0.2f, 5);
+				}
+				break;
+			}
+			case BLIP_OBJECT:
+			{
+				CEntity *entity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle);
+				if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+					CVector pos = entity->GetPosition();
+					pos.z += CModelInfo::GetModelInfo(entity->GetModelIndex())->GetColModel()->boundingBox.max.z + 1.0f + 1.0f;
+					C3dMarkers::PlaceMarker(i | (ms_RadarTrace[i].m_BlipIndex << 16), 1, pos, 1.0f, 0, 128, 255, 255, 1024, 0.2f, 5);
+				}
+				break;
+			}
+			case BLIP_COORD:
+				break;
+			case BLIP_CONTACT_POINT:
+				if (!CTheScripts::IsPlayerOnAMission()) {
+					if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY)
+						C3dMarkers::PlaceMarkerSet(i | (ms_RadarTrace[i].m_BlipIndex << 16), 4, ms_RadarTrace[i].m_vecPos, 2.0f, 0, 128, 255, 128, 2048, 0.2f, 0);
+				}
+				break;
+			}
+		}
+	}
+}
+
+void CRadar::DrawBlips()
+{
+	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
+		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+
+		CVector2D out;
+		CVector2D in = CVector2D(0.0f, 0.0f);
+		TransformRadarPointToScreenSpace(out, in);
+
+#ifdef MENU_MAP
+		if (!CMenuManager::bMenuMapActive) {
+#endif
+			float angle;
+			if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN)
+				angle = PI + FindPlayerHeading();
+#ifdef FIX_BUGS
+			else if (TheCamera.GetLookDirection() != LOOKING_FORWARD)
+				angle = FindPlayerHeading() - (PI + (TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind).Heading());
+#endif
+			else
+				angle = FindPlayerHeading() - (PI + TheCamera.GetForward().Heading());
+
+			DrawRotatingRadarSprite(&CentreSprite, out.x, out.y, angle, 255);
+
+			CVector2D vec2d;
+			vec2d.x = vec2DRadarOrigin.x;
+			vec2d.y = M_SQRT2 * m_radarRange + vec2DRadarOrigin.y;
+			TransformRealWorldPointToRadarSpace(in, vec2d);
+			LimitRadarPoint(in);
+			TransformRadarPointToScreenSpace(out, in);
+			DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255);
+#ifdef MENU_MAP
+		}
+#endif
+
+		CEntity *blipEntity = nil;
+		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
+#ifdef MENU_MAP
+			// A little hack to reuse cleared blips in menu map. hehe
+			if (!CMenuManager::bMenuMapActive || ms_RadarTrace[blipId].m_eBlipType == BLIP_CAR ||
+				ms_RadarTrace[blipId].m_eBlipType == BLIP_CHAR || ms_RadarTrace[blipId].m_eBlipType == BLIP_OBJECT)
+#endif
+			if (!ms_RadarTrace[blipId].m_bInUse)
+				continue;
+
+			switch (ms_RadarTrace[blipId].m_eBlipType) {
+				case BLIP_CAR:
+				case BLIP_CHAR:
+				case BLIP_OBJECT:
+					if (ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_SAVE
+						|| ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_WEAPON) {
+
+						switch (ms_RadarTrace[blipId].m_eBlipType) {
+							case BLIP_CAR:
+								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							case BLIP_CHAR:
+								blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								if (blipEntity != nil) {
+									if (((CPed*)blipEntity)->InVehicle())
+										blipEntity = ((CPed*)blipEntity)->m_pMyVehicle;
+								}
+								break;
+							case BLIP_OBJECT:
+								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							default:
+								break;
+						}
+						if (blipEntity) {
+							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+								if (CTheScripts::IsDebugOn()) {
+									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
+									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+										ms_RadarTrace[blipId].m_Radius = 5.0f;
+								}
+							}
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
+								float dist = LimitRadarPoint(in);
+								TransformRadarPointToScreenSpace(out, in);
+								if (ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_NONE) {
+									DrawRadarSprite(ms_RadarTrace[blipId].m_eRadarSprite, out.x, out.y, CalculateBlipAlpha(dist));
+								} else {
+#ifdef TRIANGULAR_BLIPS
+									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+									CVector &blipPos = blipEntity->GetPosition();
+									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+									if (blipPos.z - pos.z <= 2.0f) {
+										if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
+										else mode = BLIP_MODE_SQUARE;
+									}
+									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+#else
+									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+								}
+							}
+						}
+					}
+					break;
+				case BLIP_COORD:
+				case BLIP_CONTACT_POINT:
+					if ((ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_SAVE
+						|| ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_eRadarSprite == RADAR_SPRITE_WEAPON)
+						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
+
+						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+							if (CTheScripts::IsDebugOn()) {
+								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
+								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+									ms_RadarTrace[blipId].m_Radius = 5.0f;
+							}
+						}
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
+							float dist = LimitRadarPoint(in);
+							TransformRadarPointToScreenSpace(out, in);
+							if (ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_NONE) {
+								DrawRadarSprite(ms_RadarTrace[blipId].m_eRadarSprite, out.x, out.y, CalculateBlipAlpha(dist));
+							} else {
+#ifdef TRIANGULAR_BLIPS
+								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
+								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+								if (blipPos.z - pos.z <= 2.0f) {
+									if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
+									else mode = BLIP_MODE_SQUARE;
+								}
+								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+#else
+								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+							}
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
+			if (!ms_RadarTrace[blipId].m_bInUse)
+				continue;
+
+			switch (ms_RadarTrace[blipId].m_eBlipType) {
+				case BLIP_CAR:
+				case BLIP_CHAR:
+				case BLIP_OBJECT:
+					if (ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_SAVE
+						&& ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_WEAPON) {
+
+						switch (ms_RadarTrace[blipId].m_eBlipType) {
+							case BLIP_CAR:
+								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							case BLIP_CHAR:
+								blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								if (blipEntity != nil) {
+									if (((CPed*)blipEntity)->InVehicle())
+										blipEntity = ((CPed*)blipEntity)->m_pMyVehicle;
+								}
+								break;
+							case BLIP_OBJECT:
+								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							default:
+								break;
+						}
+
+						if (blipEntity) {
+							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+								if (CTheScripts::IsDebugOn()) {
+									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
+									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+										ms_RadarTrace[blipId].m_Radius = 5.0f;
+								}
+							}
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
+								float dist = LimitRadarPoint(in);
+								TransformRadarPointToScreenSpace(out, in);
+								if (ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_NONE)
+									DrawRadarSprite(ms_RadarTrace[blipId].m_eRadarSprite, out.x, out.y, CalculateBlipAlpha(dist));
+								else
+#ifdef TRIANGULAR_BLIPS
+								{
+									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+									CVector &blipPos = blipEntity->GetPosition();
+									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+									if (blipPos.z - pos.z <= 2.0f) {
+										if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
+										else mode = BLIP_MODE_SQUARE;
+									}
+									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+								}
+#else
+									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+							}
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+		for (int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
+			if (!ms_RadarTrace[blipId].m_bInUse)
+				continue;
+
+			switch (ms_RadarTrace[blipId].m_eBlipType) {
+				case BLIP_COORD:
+				case BLIP_CONTACT_POINT:
+					if (ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_SAVE
+						&& ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_WEAPON
+						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
+
+						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+							if (CTheScripts::IsDebugOn()) {
+								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
+								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+									ms_RadarTrace[blipId].m_Radius = 5.0f;
+							}
+						}
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
+							float dist = LimitRadarPoint(in);
+							TransformRadarPointToScreenSpace(out, in);
+							if (ms_RadarTrace[blipId].m_eRadarSprite != RADAR_SPRITE_NONE)
+								DrawRadarSprite(ms_RadarTrace[blipId].m_eRadarSprite, out.x, out.y, CalculateBlipAlpha(dist));
+							else
+#ifdef TRIANGULAR_BLIPS
+							{
+								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
+								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+								if (blipPos.z - pos.z <= 2.0f) {
+									if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
+									else mode = BLIP_MODE_SQUARE;
+								}
+								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+							}
+#else
+								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+#ifdef MENU_MAP
+		if (CMenuManager::bMenuMapActive) {
+			CVector2D in, out;
+			TransformRealWorldPointToRadarSpace(in, FindPlayerCentreOfWorld_NoSniperShift());
+			TransformRadarPointToScreenSpace(out, in);
+			DrawYouAreHereSprite(out.x, out.y);
+		}
+#endif
+	}
+}
+
+void CRadar::DrawMap()
+{
+	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
+#if 1 // from VC
+		CalculateCachedSinCos();
+#endif
+		if (FindPlayerVehicle()) {
+			float speed = FindPlayerSpeed().Magnitude();
+			if (speed < RADAR_MIN_SPEED)
+				m_radarRange = RADAR_MIN_RANGE;
+			else if (speed < RADAR_MAX_SPEED)
+				m_radarRange = (speed - RADAR_MIN_SPEED)/(RADAR_MAX_SPEED-RADAR_MIN_SPEED) * (RADAR_MAX_RANGE-RADAR_MIN_RANGE) + RADAR_MIN_RANGE;
+			else
+				m_radarRange = RADAR_MAX_RANGE;
+		}
+		else
+			m_radarRange = RADAR_MIN_RANGE;
+
+		vec2DRadarOrigin = CVector2D(FindPlayerCentreOfWorld_NoSniperShift());
+		DrawRadarMap();
+	}
+}
+
+void CRadar::DrawRadarMap()
+{
+	// Game calculates an unused CRect here
+
+	DrawRadarMask();
+
+	// top left ist (0, 0)
+	int x = floorf((vec2DRadarOrigin.x - WORLD_MIN_X) / RADAR_TILE_SIZE);
+	int y = ceilf((RADAR_NUM_TILES - 1) - (vec2DRadarOrigin.y - WORLD_MIN_Y) / RADAR_TILE_SIZE);
+	StreamRadarSections(x, y);
+
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+	RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE);
+
+	DrawRadarSection(x - 1, y - 1);
+	DrawRadarSection(x, y - 1);
+	DrawRadarSection(x + 1, y - 1);
+	DrawRadarSection(x - 1, y);
+	DrawRadarSection(x, y);
+	DrawRadarSection(x + 1, y);
+	DrawRadarSection(x - 1, y + 1);
+	DrawRadarSection(x, y + 1);
+	DrawRadarSection(x + 1, y + 1);
+}
+
+void CRadar::DrawRadarMask() 
+{ 
+	CVector2D corners[4] = {
+		CVector2D(1.0f, -1.0f),
+		CVector2D(1.0f, 1.0f),
+		CVector2D(-1.0f, 1.0f),
+		CVector2D(-1.0, -1.0f)
+	};
+
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDZERO);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+
+	CVector2D out[8];
+	CVector2D in;
+
+	// Draw the shape we want to mask out from the radar in four segments
+	for (int i = 0; i < 4; i++) {
+		// First point is always the corner itself
+		in.x = corners[i].x;
+		in.y = corners[i].y;
+		TransformRadarPointToScreenSpace(out[0], in);
+
+		// Then generate a quarter of the circle
+		for (int j = 0; j < 7; j++) {
+			in.x = corners[i].x * Cos(j * (PI / 2.0f / 6.0f));
+			in.y = corners[i].y * Sin(j * (PI / 2.0f / 6.0f));
+			TransformRadarPointToScreenSpace(out[j + 1], in);
+		};
+
+		CSprite2d::SetMaskVertices(8, (float *)out);
+		RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8);
+	};
+}
+
+void CRadar::DrawRadarSection(int32 x, int32 y)
+{
+	int i;
+	RwTexDictionary *txd;
+	CVector2D worldPoly[8];
+	CVector2D radarCorners[4];
+	CVector2D radarPoly[8];
+	CVector2D texCoords[8];
+	CVector2D screenPoly[8];
+	int numVertices;
+	RwTexture *texture = nil;
+
+	GetTextureCorners(x, y, worldPoly);
+	ClipRadarTileCoords(x, y);
+
+	assert(CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y]));
+	txd = CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])->texDict;
+	if (txd)
+		texture = GetFirstTexture(txd);
+	if (texture == nil)
+		return;
+
+	for (i = 0; i < 4; i++)
+		TransformRealWorldPointToRadarSpace(radarCorners[i], worldPoly[i]);
+
+	numVertices = ClipRadarPoly(radarPoly, radarCorners);
+
+	// FIX: can return earlier here
+//	if(numVertices == 0)
+	if (numVertices < 3)
+		return;
+
+	for (i = 0; i < numVertices; i++) {
+		TransformRadarPointToRealWorldSpace(worldPoly[i], radarPoly[i]);
+		TransformRealWorldToTexCoordSpace(texCoords[i], worldPoly[i], x, y);
+		TransformRadarPointToScreenSpace(screenPoly[i], radarPoly[i]);
+	}
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(texture));
+	CSprite2d::SetVertices(numVertices, (float*)screenPoly, (float*)texCoords, CRGBA(255, 255, 255, 255));
+	// check done above now
+//	if(numVertices > 2)
+	RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices);
+}
+
+void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha)
+{
+	RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
+#ifdef MENU_MAP
+	if (CMenuManager::bMenuMapActive) {
+		bool alreadyThere = false;
+		for (int i = 0; i < NUM_MAP_LEGENDS; i++) {
+			if (MapLegendList[i] == sprite)
+				alreadyThere = true;
+		}
+		if (!alreadyThere) {
+			MapLegendList[MapLegendCounter] = sprite;
+			MapLegendCounter++;
+		}
+	}
+#endif
+}
+
+void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha)
+{
+	CVector curPosn[4];
+	CVector oldPosn[4];
+
+	curPosn[0].x = x - SCREEN_SCALE_X(5.6f);
+	curPosn[0].y = y + SCREEN_SCALE_Y(5.6f);
+
+	curPosn[1].x = x + SCREEN_SCALE_X(5.6f);
+	curPosn[1].y = y + SCREEN_SCALE_Y(5.6f);
+
+	curPosn[2].x = x - SCREEN_SCALE_X(5.6f);
+	curPosn[2].y = y - SCREEN_SCALE_Y(5.6f);
+
+	curPosn[3].x = x + SCREEN_SCALE_X(5.6f);
+	curPosn[3].y = y - SCREEN_SCALE_Y(5.6f);
+
+	for (uint32 i = 0; i < 4; i++) {
+		oldPosn[i] = curPosn[i];
+
+		curPosn[i].x = x + (oldPosn[i].x - x) * Cos(angle) + (oldPosn[i].y - y) * Sin(angle);
+		curPosn[i].y = y - (oldPosn[i].x - x) * Sin(angle) + (oldPosn[i].y - y) * Cos(angle);
+	}
+
+	sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
+}
+
+int32 CRadar::GetActualBlipArrayIndex(int32 i)
+{
+	if (i == -1)
+		return -1;
+	else if ((i & 0xFFFF0000) >> 16 != ms_RadarTrace[(uint16)i].m_BlipIndex)
+		return -1;
+	else
+		return (uint16)i;
+}
+
+int32 CRadar::GetNewUniqueBlipIndex(int32 i)
+{
+	if (ms_RadarTrace[i].m_BlipIndex >= UINT16_MAX - 1)
+		ms_RadarTrace[i].m_BlipIndex = 1;
+	else
+		ms_RadarTrace[i].m_BlipIndex++;
+	return i | (ms_RadarTrace[i].m_BlipIndex << 16);
+}
+
+uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright)
+{
+	int32 c;
+	switch (color) {
+	case 0:
+		if (bright)
+			c = 0x712B49FF;
+		else
+			c = 0x7F0000FF;
+		break;
+	case 1:
+		if (bright)
+			c = 0x5FA06AFF;
+		else
+			c = 0x007F00FF;
+		break;
+	case 2:
+		if (bright)
+			c = 0x80A7F3FF;
+		else
+			c = 0x00007FFF;
+		break;
+	case 3:
+		if (bright)
+			c = 0xE1E1E1FF;
+		else
+			c = 0x7F7F7FFF;
+		break;
+	case 4:
+		if (bright)
+			c = 0xFFFF00FF;
+		else
+			c = 0x7F7F00FF;
+		break;
+	case 5:
+		if (bright)
+			c = 0xFF00FFFF;
+		else
+			c = 0x7F007FFF;
+		break;
+	case 6:
+		if (bright)
+			c = 0x00FFFFFF;
+		else
+			c = 0x007F7FFF;
+		break;
+	default:
+		c = color;
+		break;
+	};
+	return c;
+}
+
+const char* gRadarTexNames[] = {
+	"radar00", "radar01", "radar02", "radar03", "radar04", "radar05", "radar06", "radar07",
+	"radar08", "radar09", "radar10", "radar11", "radar12", "radar13", "radar14", "radar15",
+	"radar16", "radar17", "radar18", "radar19", "radar20", "radar21", "radar22", "radar23",
+	"radar24", "radar25", "radar26", "radar27", "radar28", "radar29", "radar30", "radar31",
+	"radar32", "radar33", "radar34", "radar35", "radar36", "radar37", "radar38", "radar39",
+	"radar40", "radar41", "radar42", "radar43", "radar44", "radar45", "radar46", "radar47",
+	"radar48", "radar49", "radar50", "radar51", "radar52", "radar53", "radar54", "radar55",
+	"radar56", "radar57", "radar58", "radar59", "radar60", "radar61", "radar62", "radar63",
+};
+
+void
+CRadar::Initialise()
+{
+	for (int i = 0; i < NUMRADARBLIPS; i++) {
+		ms_RadarTrace[i].m_BlipIndex = 1;
+		SetRadarMarkerState(i, false);
+		ms_RadarTrace[i].m_bInUse = false;
+		ms_RadarTrace[i].m_eBlipType = BLIP_NONE;
+		ms_RadarTrace[i].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
+		ms_RadarTrace[i].m_eRadarSprite = RADAR_SPRITE_NONE;
+	}
+
+	m_radarRange = 350.0f;
+	for (int i = 0; i < 64; i++) 
+		gRadarTxdIds[i] = CTxdStore::FindTxdSlot(gRadarTexNames[i]);
+}
+
+float CRadar::LimitRadarPoint(CVector2D &point)
+{
+	float dist, invdist;
+
+	dist = point.Magnitude();
+#ifdef MENU_MAP
+	if (CMenuManager::bMenuMapActive)
+		return dist;
+#endif
+	if (dist > 1.0f) {
+		invdist = 1.0f / dist;
+		point.x *= invdist;
+		point.y *= invdist;
+	}
+	return dist;
+}
+
+void CRadar::LoadAllRadarBlips(uint8 *buf, uint32 size)
+{
+	Initialise();
+INITSAVEBUF
+	CheckSaveHeader(buf, 'R', 'D', 'R', '\0', size - SAVE_HEADER_SIZE);
+
+	for (int i = 0; i < NUMRADARBLIPS; i++)
+		ms_RadarTrace[i] = ReadSaveBuf<sRadarTrace>(buf);
+
+VALIDATESAVEBUF(size);
+}
+
+void
+CRadar::LoadTextures()
+{
+	CTxdStore::PushCurrentTxd();
+	CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("hud"));
+	AsukaSprite.SetTexture("radar_asuka");
+	BombSprite.SetTexture("radar_bomb");
+	CatSprite.SetTexture("radar_cat");
+	CentreSprite.SetTexture("radar_centre");
+	CopcarSprite.SetTexture("radar_copcar");
+	DonSprite.SetTexture("radar_don");
+	EightSprite.SetTexture("radar_eight");
+	ElSprite.SetTexture("radar_el");
+	IceSprite.SetTexture("radar_ice");
+	JoeySprite.SetTexture("radar_joey");
+	KenjiSprite.SetTexture("radar_kenji");
+	LizSprite.SetTexture("radar_liz");
+	LuigiSprite.SetTexture("radar_luigi");
+	NorthSprite.SetTexture("radar_north");
+	RaySprite.SetTexture("radar_ray");
+	SalSprite.SetTexture("radar_sal");
+	SaveSprite.SetTexture("radar_save");
+	SpraySprite.SetTexture("radar_spray");
+	TonySprite.SetTexture("radar_tony");
+	WeaponSprite.SetTexture("radar_weapon");
+	CTxdStore::PopCurrentTxd();
+}
+
+void CRadar::RemoveRadarSections()
+{
+	for (int i = 0; i < 8; i++)
+		for (int j = 0; j < 8; j++)
+			RemoveMapSection(i, j);
+}
+
+void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size)
+{
+	*size = SAVE_HEADER_SIZE + sizeof(ms_RadarTrace);
+INITSAVEBUF
+	WriteSaveHeader(buf, 'R', 'D', 'R', '\0', *size - SAVE_HEADER_SIZE);
+
+	for (int i = 0; i < NUMRADARBLIPS; i++)
+		WriteSaveBuf(buf, ms_RadarTrace[i]);
+
+VALIDATESAVEBUF(*size);
+}
+
+void CRadar::SetBlipSprite(int32 i, int32 icon)
+{
+	int index = CRadar::GetActualBlipArrayIndex(i);
+	if (index != -1) {
+		ms_RadarTrace[index].m_eRadarSprite = icon;
+	}
+}
+
+int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay display)
+{
+	int nextBlip;
+	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
+		if (!ms_RadarTrace[nextBlip].m_bInUse)
+			break;
+	}
+	ms_RadarTrace[nextBlip].m_eBlipType = type;
+	ms_RadarTrace[nextBlip].m_nColor = color;
+	ms_RadarTrace[nextBlip].m_bDim = 1;
+	ms_RadarTrace[nextBlip].m_bInUse = 1;
+	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
+	ms_RadarTrace[nextBlip].m_vec2DPos = pos;
+	ms_RadarTrace[nextBlip].m_vecPos = pos;
+	ms_RadarTrace[nextBlip].m_nEntityHandle = 0;
+	ms_RadarTrace[nextBlip].m_wScale = 1;
+	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
+	ms_RadarTrace[nextBlip].m_eRadarSprite = RADAR_SPRITE_NONE;
+	return CRadar::GetNewUniqueBlipIndex(nextBlip);
+}
+
+int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDisplay display)
+{
+	int nextBlip;
+	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
+		if (!ms_RadarTrace[nextBlip].m_bInUse)
+			break;
+	}
+	ms_RadarTrace[nextBlip].m_eBlipType = type;
+	ms_RadarTrace[nextBlip].m_nColor = color;
+	ms_RadarTrace[nextBlip].m_bDim = 1;
+	ms_RadarTrace[nextBlip].m_bInUse = 1;
+	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
+	ms_RadarTrace[nextBlip].m_nEntityHandle = handle;
+	ms_RadarTrace[nextBlip].m_wScale = 1;
+	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
+	ms_RadarTrace[nextBlip].m_eRadarSprite = RADAR_SPRITE_NONE;
+	return GetNewUniqueBlipIndex(nextBlip);
+}
+
+void CRadar::SetRadarMarkerState(int32 counter, bool flag)
+{
+	CEntity *e;
+	switch (ms_RadarTrace[counter].m_eBlipType) {
+	case BLIP_CAR:
+		e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+		break;
+	case BLIP_CHAR:
+		e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+		break;
+	case BLIP_OBJECT:
+		e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+		break;
+	default:
+		return;
+	}
+
+	if (e)
+		e->bHasBlip = flag;
+}
+
+void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) {
+	float f1 = radius * 1.4f;
+	float f2 = radius * 0.5f;
+	CVector p1, p2;
+
+	p1 = pos + TheCamera.GetUp()*f1;
+	p2 = pos + TheCamera.GetUp()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+	p1 = pos - TheCamera.GetUp()*f1;
+	p2 = pos - TheCamera.GetUp()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+	p1 = pos + TheCamera.GetRight()*f1;
+	p2 = pos + TheCamera.GetRight()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+	p1 = pos - TheCamera.GetRight()*f1;
+	p2 = pos - TheCamera.GetRight()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+}
+
+void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha)
+{
+	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
+		return;
+
+	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
+	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
+}
+
+void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint8 mode)
+{
+	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
+		return;
+
+	switch (mode)
+	{
+	case BLIP_MODE_TRIANGULAR_UP:
+		// size++; // VC does size + 1 for triangles
+		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 3.0f), y + SCREEN_SCALE_Y(size + 2.0f), x - (SCREEN_SCALE_X(size + 3.0f)), y + SCREEN_SCALE_Y(size + 2.0f), x, y - (SCREEN_SCALE_Y(size + 3.0f)), x, y - (SCREEN_SCALE_Y(size + 3.0f)), CRGBA(0, 0, 0, alpha));
+		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 1.0f), y + SCREEN_SCALE_Y(size + 1.0f), x - (SCREEN_SCALE_X(size + 1.0f)), y + SCREEN_SCALE_Y(size + 1.0f), x, y - (SCREEN_SCALE_Y(size + 1.0f)), x, y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
+		break;
+	case BLIP_MODE_TRIANGULAR_DOWN:
+		// size++; // VC does size + 1 for triangles
+		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 2.0f), x, y + SCREEN_SCALE_Y(size + 3.0f), x + SCREEN_SCALE_X(size + 3.0f), y - (SCREEN_SCALE_Y(size + 2.0f)), x - (SCREEN_SCALE_X(size + 3.0f)), y - (SCREEN_SCALE_Y(size + 2.0f)), CRGBA(0, 0, 0, alpha));
+		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 1.0f), x, y + SCREEN_SCALE_Y(size + 1.0f), x + SCREEN_SCALE_X(size + 1.0f), y - (SCREEN_SCALE_Y(size + 1.0f)), x - (SCREEN_SCALE_X(size + 1.0f)), y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
+		break;
+	case BLIP_MODE_SQUARE:
+		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
+		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
+		break;
+	}
+#ifdef MENU_MAP
+	// VC uses -1 for coords and -2 for entities but meh, I don't want to edit DrawBlips
+	if (CMenuManager::bMenuMapActive) {
+		bool alreadyThere = false;
+		for (int i = 0; i < NUM_MAP_LEGENDS; i++) {
+			if (MapLegendList[i] == -1)
+				alreadyThere = true;
+		}
+		if (!alreadyThere) {
+			MapLegendList[MapLegendCounter] = -1;
+			MapLegendCounter++;
+			ArrowBlipColour1 = CRGBA(red, green, blue, alpha);
+		}
+	}
+#endif
+}
+
+void CRadar::Shutdown()
+{
+	AsukaSprite.Delete();
+	BombSprite.Delete();
+	CatSprite.Delete();
+	CentreSprite.Delete();
+	CopcarSprite.Delete();
+	DonSprite.Delete();
+	EightSprite.Delete();
+	ElSprite.Delete();
+	IceSprite.Delete();
+	JoeySprite.Delete();
+	KenjiSprite.Delete();
+	LizSprite.Delete();
+	LuigiSprite.Delete();
+	NorthSprite.Delete();
+	RaySprite.Delete();
+	SalSprite.Delete();
+	SaveSprite.Delete();
+	SpraySprite.Delete();
+	TonySprite.Delete();
+	WeaponSprite.Delete();
+	RemoveRadarSections();
+}
+
+void CRadar::StreamRadarSections(const CVector &posn)
+{
+	StreamRadarSections(floorf((2000.0f + posn.x) / 500.0f), ceilf(7.0f - (2000.0f + posn.y) / 500.0f));
+}
+
+void CRadar::StreamRadarSections(int32 x, int32 y)
+{
+	for (int i = 0; i < RADAR_NUM_TILES; ++i) {
+		for (int j = 0; j < RADAR_NUM_TILES; ++j) {
+			if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1))
+				RequestMapSection(i, j);
+			else
+				RemoveMapSection(i, j);
+		};
+	};
+}
+
+void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y)
+{
+	out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X);
+	out.y = -(in.y - ((RADAR_NUM_TILES - y) * RADAR_TILE_SIZE + WORLD_MIN_Y));
+	out.x /= RADAR_TILE_SIZE;
+	out.y /= RADAR_TILE_SIZE;
+}
+
+void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
+{
+	float s, c;
+#if 1
+	s = -cachedSin;
+	c = cachedCos;
+#else
+	// Original code
+
+	s = -Sin(TheCamera.GetForward().Heading());
+	c = Cos(TheCamera.GetForward().Heading());
+
+	if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) {
+		s = 0.0f;
+		c = 1.0f;
+	}
+	else if (TheCamera.GetLookDirection() != LOOKING_FORWARD) {
+		CVector forward;
+
+		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) {
+			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
+			forward.Normalise();	// a bit useless...
+		}
+		else
+			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
+
+		s = -Sin(forward.Heading());
+		c = Cos(forward.Heading());
+	}
+#endif
+
+	out.x = s * in.y + c * in.x;
+	out.y = c * in.y - s * in.x;
+
+	out = out * m_radarRange + vec2DRadarOrigin;
+}
+
+// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0)
+void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in)
+{
+#ifdef MENU_MAP
+	if (CMenuManager::bMenuMapActive) {
+		// fMapSize is actually half map size. Radar range is 1000, so if x is -2000, in.x + 2.0f is 0.
+		out.x = (CMenuManager::fMapCenterX - CMenuManager::fMapSize) + (in.x + 2.0f) * CMenuManager::fMapSize * 2.0f / 4.0f;
+		out.y = (CMenuManager::fMapCenterY - CMenuManager::fMapSize) + (2.0f - in.y) * CMenuManager::fMapSize * 2.0f / 4.0f;
+	} else
+#endif
+	{
+#ifdef FIX_BUGS
+		out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT);
+#else
+		out.x = (in.x + 1.0f) * 0.5f * SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT;
+#endif
+		out.y = (1.0f - in.y) * 0.5f * SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT);
+	}
+}
+
+void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
+{
+	float s, c;
+#if 1
+	s = cachedSin;
+	c = cachedCos;
+#else
+	// Original code
+
+	float s, c;
+	if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) {
+		s = 0.0f;
+		c = 1.0f;
+	}
+	else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) {
+		s = Sin(TheCamera.GetForward().Heading());
+		c = Cos(TheCamera.GetForward().Heading());
+	}
+	else {
+		CVector forward;
+
+		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) {
+			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
+			forward.Normalise();	// a bit useless...
+		}
+		else
+			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
+
+		s = Sin(forward.Heading());
+		c = Cos(forward.Heading());
+	}
+#endif
+
+	float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_radarRange);
+	float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_radarRange);
+
+	out.x = s * y + c * x;
+	out.y = c * y - s * x;
+}
+
+void
+CRadar::CalculateCachedSinCos()
+{
+	if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED
+#ifdef MENU_MAP
+		|| CMenuManager::bMenuMapActive
+#endif
+		) {
+		cachedSin = 0.0f;
+		cachedCos = 1.0f;
+	} else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) {
+		cachedSin = Sin(TheCamera.GetForward().Heading());
+		cachedCos = Cos(TheCamera.GetForward().Heading());
+	} else {
+		CVector forward;
+
+		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) {
+			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
+			forward.Normalise();	// a bit useless...
+		}
+		else
+			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
+
+		cachedSin = Sin(forward.Heading());
+		cachedCos = Cos(forward.Heading());
+	}
+}
+
+#ifdef MENU_MAP
+void
+CRadar::InitFrontEndMap()
+{
+	CalculateCachedSinCos();
+	vec2DRadarOrigin.x = 0.0f;
+	vec2DRadarOrigin.y = 0.0f;
+	m_radarRange = 1000.0f; // doesn't mean anything, just affects the calculation in TransformRadarPointToScreenSpace
+	for (int i = 0; i < NUM_MAP_LEGENDS; i++) {
+		MapLegendList[i] = RADAR_SPRITE_NONE;
+	}
+	MapLegendCounter = 0;
+	ArrowBlipColour1 = CRGBA(0, 0, 0, 0);
+	ArrowBlipColour2 = CRGBA(0, 0, 0, 0);
+}
+
+void
+CRadar::DrawYouAreHereSprite(float x, float y)
+{
+	static uint32 lastChange = 0;
+	static bool show = true;
+
+	if (show) {
+		if (CTimer::GetTimeInMillisecondsPauseMode() - lastChange > 500) {
+			lastChange = CTimer::GetTimeInMillisecondsPauseMode();
+			show = !show;
+		}
+	} else {
+		if (CTimer::GetTimeInMillisecondsPauseMode() - lastChange > 200) {
+			lastChange = CTimer::GetTimeInMillisecondsPauseMode();
+			show = !show;
+		}
+	}
+
+	if (show) {
+		float left = x - SCREEN_SCALE_X(12.0f);
+		float top = y - SCREEN_SCALE_Y(2.0f);
+		float right = SCREEN_SCALE_X(12.0) + x;
+		float bottom = y - SCREEN_SCALE_Y(26.0f);
+		CentreSprite.Draw(CRect(left, top, right, bottom), CRGBA(255, 255, 255, 255));
+	}
+	MapLegendList[MapLegendCounter++] = RADAR_SPRITE_CENTRE;
+}
+
+void
+CRadar::ToggleTargetMarker(float x, float y)
+{
+	if (TargetMarkerId == -1) {
+		int nextBlip;
+		for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
+			if (!ms_RadarTrace[nextBlip].m_bInUse)
+				break;
+		}
+		ms_RadarTrace[nextBlip].m_eBlipType = BLIP_COORD;
+		ms_RadarTrace[nextBlip].m_nColor = 0x333333FF;
+		ms_RadarTrace[nextBlip].m_bDim = 1;
+		ms_RadarTrace[nextBlip].m_bInUse = 1;
+		ms_RadarTrace[nextBlip].m_Radius = 1.0f;
+		CVector pos(x, y, CWorld::FindGroundZForCoord(x,y));
+		ms_RadarTrace[nextBlip].m_vec2DPos = pos;
+		ms_RadarTrace[nextBlip].m_vecPos = pos;
+		ms_RadarTrace[nextBlip].m_nEntityHandle = 0;
+		ms_RadarTrace[nextBlip].m_wScale = 5;
+		ms_RadarTrace[nextBlip].m_eBlipDisplay = BLIP_DISPLAY_BLIP_ONLY;
+		ms_RadarTrace[nextBlip].m_eRadarSprite = RADAR_SPRITE_NONE;
+		TargetMarkerId = CRadar::GetNewUniqueBlipIndex(nextBlip);
+	} else {
+		ClearBlip(TargetMarkerId);
+		TargetMarkerId = -1;
+	}
+}
+#endif
+
+STARTPATCHES
+	InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP);
+	InjectHook(0x4A3F60, CRadar::Shutdown, PATCH_JUMP);
+	InjectHook(0x4A4030, CRadar::LoadTextures, PATCH_JUMP);
+	InjectHook(0x4A4180, CRadar::GetNewUniqueBlipIndex, PATCH_JUMP);
+	InjectHook(0x4A41C0, CRadar::GetActualBlipArrayIndex, PATCH_JUMP);
+	InjectHook(0x4A4200, CRadar::DrawMap, PATCH_JUMP);
+	InjectHook(0x4A42F0, CRadar::DrawBlips, PATCH_JUMP);
+	InjectHook(0x4A4C70, CRadar::Draw3dMarkers, PATCH_JUMP);
+	InjectHook(0x4A4F30, CRadar::LimitRadarPoint, PATCH_JUMP);
+	InjectHook(0x4A4F90, CRadar::CalculateBlipAlpha, PATCH_JUMP);
+	InjectHook(0x4A5040, CRadar::TransformRadarPointToScreenSpace, PATCH_JUMP);
+	InjectHook(0x4A50D0, CRadar::TransformRealWorldPointToRadarSpace, PATCH_JUMP);
+	InjectHook(0x4A5300, CRadar::TransformRadarPointToRealWorldSpace, PATCH_JUMP);
+	InjectHook(0x4A5530, CRadar::TransformRealWorldToTexCoordSpace, PATCH_JUMP);
+	InjectHook(0x4A5590, CRadar::SetCoordBlip, PATCH_JUMP);
+	InjectHook(0x4A5640, CRadar::SetEntityBlip, PATCH_JUMP);
+	InjectHook(0x4A56C0, CRadar::ClearBlipForEntity, PATCH_JUMP);
+	InjectHook(0x4A5720, CRadar::ClearBlip, PATCH_JUMP);
+	InjectHook(0x4A5770, CRadar::ChangeBlipColour, PATCH_JUMP);
+	InjectHook(0x4A57A0, CRadar::ChangeBlipBrightness, PATCH_JUMP);
+	InjectHook(0x4A57E0, CRadar::ChangeBlipScale, PATCH_JUMP);
+	InjectHook(0x4A5810, CRadar::ChangeBlipDisplay, PATCH_JUMP);
+	InjectHook(0x4A5840, CRadar::SetBlipSprite, PATCH_JUMP);
+	InjectHook(0x4A5870, CRadar::ShowRadarTrace, PATCH_JUMP);
+	InjectHook(0x4A59C0, CRadar::ShowRadarMarker, PATCH_JUMP);
+	InjectHook(0x4A5BB0, CRadar::GetRadarTraceColour, PATCH_JUMP);
+	InjectHook(0x4A5C60, CRadar::SetRadarMarkerState, PATCH_JUMP);
+	InjectHook(0x4A5D10, CRadar::DrawRotatingRadarSprite, PATCH_JUMP);
+	InjectHook(0x4A5EF0, CRadar::DrawRadarSprite, PATCH_JUMP);
+	InjectHook(0x4A6020, ClipRadarTileCoords, PATCH_JUMP);
+	InjectHook(0x4A6060, RequestMapSection, PATCH_JUMP);
+	InjectHook(0x4A60A0, RemoveMapSection, PATCH_JUMP);
+	InjectHook(0x4A60E0, CRadar::RemoveRadarSections, PATCH_JUMP);
+	InjectHook(0x4A6100, (void (*)(int32, int32))&CRadar::StreamRadarSections, PATCH_JUMP);
+	InjectHook(0x4A6160, IsPointInsideRadar, PATCH_JUMP);
+	InjectHook(0x4A61C0, GetTextureCorners, PATCH_JUMP);
+	InjectHook(0x4A6250, LineRadarBoxCollision, PATCH_JUMP);
+	InjectHook(0x4A64A0, CRadar::ClipRadarPoly, PATCH_JUMP);
+	InjectHook(0x4A67E0, CRadar::DrawRadarSection, PATCH_JUMP);
+	InjectHook(0x4A69C0, CRadar::DrawRadarMask, PATCH_JUMP);
+	InjectHook(0x4A6B60, (void (*)(const CVector&))&CRadar::StreamRadarSections, PATCH_JUMP);
+	InjectHook(0x4A6C20, CRadar::DrawRadarMap, PATCH_JUMP);
+	InjectHook(0x4A6E30, CRadar::SaveAllRadarBlips, PATCH_JUMP);
+	InjectHook(0x4A6F30, CRadar::LoadAllRadarBlips, PATCH_JUMP);
+	//InjectHook(0x4A7000, `global constructor keyed to'Radar.cpp, PATCH_JUMP);
+	//InjectHook(0x4A7260, sRadarTrace::sRadarTrace, PATCH_JUMP);
+ENDPATCHES
\ No newline at end of file
diff --git a/src/core/Radar.h b/src/core/Radar.h
index b0400b0d..27f3a6f0 100644
--- a/src/core/Radar.h
+++ b/src/core/Radar.h
@@ -21,6 +21,10 @@ enum eBlipDisplay
 
 enum eRadarSprite
 {
+#ifdef MENU_MAP
+	RADAR_SPRITE_ENTITY_BLIP = -2,
+	RADAR_SPRITE_COORD_BLIP = -1,
+#endif
 	RADAR_SPRITE_NONE = 0,
 	RADAR_SPRITE_ASUKA = 1,
 	RADAR_SPRITE_BOMB = 2,
@@ -52,7 +56,7 @@ enum
 	BLIP_MODE_SQUARE,
 };
 
-struct CBlip
+struct sRadarTrace
 {
 	uint32 m_nColor;
 	uint32 m_eBlipType; // eBlipType
@@ -65,9 +69,9 @@ struct CBlip
 	float m_Radius;
 	int16 m_wScale;
 	uint16 m_eBlipDisplay; // eBlipDisplay
-	uint16 m_IconID; // eRadarSprite
+	uint16 m_eRadarSprite; // eRadarSprite
 };
-static_assert(sizeof(CBlip) == 0x30, "CBlip: error");
+static_assert(sizeof(sRadarTrace) == 0x30, "sRadarTrace: error");
 
 // Values for screen space
 #define RADAR_LEFT (40.0f)
@@ -79,7 +83,7 @@ class CRadar
 {
 public:
 	static float &m_radarRange;
-	static CBlip (&ms_RadarTrace)[NUMRADARBLIPS];
+	static sRadarTrace (&ms_RadarTrace)[NUMRADARBLIPS];
 	static CSprite2d AsukaSprite;
 	static CSprite2d BombSprite;
 	static CSprite2d CatSprite;
@@ -101,8 +105,20 @@ public:
 	static CSprite2d TonySprite;
 	static CSprite2d WeaponSprite;
 	static CSprite2d *RadarSprites[21];
+	static float cachedCos;
+	static float cachedSin;
+#ifdef MENU_MAP
+#define NUM_MAP_LEGENDS 75
+	static CRGBA ArrowBlipColour1;
+	static CRGBA ArrowBlipColour2;
+	static uint16 MapLegendList[NUM_MAP_LEGENDS];
+	static uint16 MapLegendCounter;
+	static int TargetMarkerId;
 
-public:
+	static void InitFrontEndMap();
+	static void DrawYouAreHereSprite(float, float);
+	static void ToggleTargetMarker(float, float);
+#endif
 	static uint8 CalculateBlipAlpha(float dist);
 	static void ChangeBlipBrightness(int32 i, int32 bright);
 	static void ChangeBlipColour(int32 i, int32);
@@ -128,7 +144,6 @@ public:
 	static void LoadAllRadarBlips(uint8 *buf, uint32 size);
 	static void LoadTextures();
 	static void RemoveRadarSections();
-	static void RequestMapSection(int32 x, int32 y);
 	static void SaveAllRadarBlips(uint8*, uint32*);
 	static void SetBlipSprite(int32 i, int32 icon);
 	static int32 SetCoordBlip(eBlipType type, CVector pos, int32, eBlipDisplay);
@@ -145,9 +160,6 @@ public:
 	static void TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in);
 	static void TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in);
 
-	// no in CRadar in the game:
-	static void GetTextureCorners(int32 x, int32 y, CVector2D *out);
-	static void ClipRadarTileCoords(int32 &x, int32 &y);
-	static bool IsPointInsideRadar(const CVector2D &);
-	static int LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &);
+	// no in CRadar in the game:	
+	static void CalculateCachedSinCos();
 };
diff --git a/src/core/RwTexRead.cpp b/src/core/RwTexRead.cpp
deleted file mode 100644
index 6b717b34..00000000
--- a/src/core/RwTexRead.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-#pragma warning( push )
-#pragma warning( disable : 4005)
-#define DIRECTINPUT_VERSION 0x0800
-#include <dinput.h>
-#pragma warning( pop )
-#include "common.h"
-#include "win.h"
-#include "patcher.h"
-#include "Timer.h"
-
-float &texLoadTime = *(float*)0x8F1B50;
-int32 &texNumLoaded = *(int32*)0x8F252C;
-
-RwTexture*
-RwTextureGtaStreamRead(RwStream *stream)
-{
-	RwUInt32 size, version;
-	RwTexture *tex;
-
-	if(!RwStreamFindChunk(stream, rwID_TEXTURENATIVE, &size, &version))
-		return nil;
-
-	float preloadTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
-
-	if(!RWSRCGLOBAL(stdFunc[rwSTANDARDNATIVETEXTUREREAD](stream, &tex, size)))
-		return nil;
-
-	if (gGameState == GS_INIT_PLAYING_GAME) {
-		texLoadTime = (texNumLoaded * texLoadTime + (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond() - preloadTime) / (float)(texNumLoaded+1);
-		texNumLoaded++;
-	}
-	return tex;
-}
-
-RwTexture*
-destroyTexture(RwTexture *texture, void *data)
-{
-	RwTextureDestroy(texture);
-	return texture;
-}
-
-RwTexDictionary*
-RwTexDictionaryGtaStreamRead(RwStream *stream)
-{
-	RwUInt32 size, version;
-	RwInt32 numTextures;
-	RwTexDictionary *texDict;
-	RwTexture *tex;
-
-	if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
-		return nil;
-	assert(size == 4);
-	if(RwStreamRead(stream, &numTextures, size) != size)
-		return nil;
-
-	texDict = RwTexDictionaryCreate();
-	if(texDict == nil)
-		return nil;
-
-	while(numTextures--){
-		tex = RwTextureGtaStreamRead(stream);
-		if(tex == nil){
-			RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
-			RwTexDictionaryDestroy(texDict);
-			return nil;
-		}
-		RwTexDictionaryAddTexture(texDict, tex);
-	}
-
-	return texDict;
-}
-
-static int32 numberTextures = -1;
-static int32 streamPosition;
-
-RwTexDictionary*
-RwTexDictionaryGtaStreamRead1(RwStream *stream)
-{
-	RwUInt32 size, version;
-	RwInt32 numTextures;
-	RwTexDictionary *texDict;
-	RwTexture *tex;
-
-	numberTextures = 0;
-	if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
-		return nil;
-	assert(size == 4);
-	if(RwStreamRead(stream, &numTextures, size) != size)
-		return nil;
-
-	texDict = RwTexDictionaryCreate();
-	if(texDict == nil)
-		return nil;
-
-	numberTextures = numTextures/2;
-
-	while(numTextures > numberTextures){
-		numTextures--;
-
-		tex = RwTextureGtaStreamRead(stream);
-		if(tex == nil){
-			RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
-			RwTexDictionaryDestroy(texDict);
-			return nil;
-		}
-		RwTexDictionaryAddTexture(texDict, tex);
-	}
-
-	numberTextures = numTextures;
-	streamPosition = stream->Type.memory.position;
-
-	return texDict;
-}
-
-RwTexDictionary*
-RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict)
-{
-	RwTexture *tex;
-
-	RwStreamSkip(stream, streamPosition - stream->Type.memory.position);
-
-	while(numberTextures--){
-		tex = RwTextureGtaStreamRead(stream);
-		if(tex == nil){
-			RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
-			RwTexDictionaryDestroy(texDict);
-			return nil;
-		}
-		RwTexDictionaryAddTexture(texDict, tex);
-	}
-
-	return texDict;
-}
-
-STARTPATCHES
-	InjectHook(0x592380, RwTextureGtaStreamRead, PATCH_JUMP);
-	InjectHook(0x5924A0, RwTexDictionaryGtaStreamRead, PATCH_JUMP);
-	InjectHook(0x592550, RwTexDictionaryGtaStreamRead1, PATCH_JUMP);
-	InjectHook(0x592650, RwTexDictionaryGtaStreamRead2, PATCH_JUMP);
-ENDPATCHES
diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp
index 9478479b..02092a30 100644
--- a/src/core/Stats.cpp
+++ b/src/core/Stats.cpp
@@ -1,18 +1,18 @@
 #include "common.h"
 #include "patcher.h"
 #include "Stats.h"
-
-WRAPPER void CStats::SaveStats(uint8 *buf, uint32 *size) { EAXJMP(0x4ab3e0); }
+#include "Text.h"
+#include "World.h"
 
 int32 &CStats::DaysPassed = *(int32*)0x8F2BB8;
 int32 &CStats::HeadsPopped = *(int32*)0x8F647C;
-bool& CStats::CommercialPassed = *(bool*)0x8F4334;
-bool& CStats::IndustrialPassed = *(bool*)0x8E2A68;
-bool& CStats::SuburbanPassed = *(bool*)0x8F2740;
+int32& CStats::CommercialPassed = *(int32*)0x8F4334;
+int32& CStats::IndustrialPassed = *(int32*)0x8E2A68;
+int32& CStats::SuburbanPassed = *(int32*)0x8F2740;
 int32 &CStats::NumberKillFrenziesPassed = *(int32*)0x8E287C;
 int32 &CStats::PeopleKilledByOthers = *(int32*)0x8E2C50;
 int32 &CStats::HelisDestroyed = *(int32*)0x8E2A64;
-int32 *CStats::PedsKilledOfThisType = (int32*)0x880DBC;
+int32(&CStats::PedsKilledOfThisType)[NUM_PEDTYPES] = *(int32(*)[NUM_PEDTYPES]) * (uintptr*)0x880DBC;
 int32 &CStats::TimesDied = *(int32*)0x8E2BDC;
 int32 &CStats::TimesArrested = *(int32*)0x8E2BEC;
 int32 &CStats::KillsSinceLastCheckpoint = *(int32*)0x8F2C8C;
@@ -48,11 +48,73 @@ int32& CStats::LongestFlightInDodo = *(int32*)0x8F5FE4;
 int32& CStats::TimeTakenDefuseMission = *(int32*)0x880E24;
 int32& CStats::TotalNumberKillFrenzies = *(int32*)0x8E2884;
 int32& CStats::TotalNumberMissions = *(int32*)0x8E2820;
-int32& CStats::KgOfExplosivesUsed = *(int32*)0x8F2510;
+int32& CStats::RoundsFiredByPlayer = *(int32*)0x8E2BE8;
+int32& CStats::KgsOfExplosivesUsed = *(int32*)0x8F2510;
+int32& CStats::InstantHitsFiredByPlayer = *(int32*)0x943070;
+int32& CStats::InstantHitsHitByPlayer = *(int32*)0x95CB8C;
+int32& CStats::BestTimeBombDefusal = *(int32*)0x880E24;
+int32& CStats::mmRain = *(int32*)0x8F2C98;
 int32& CStats::CarsCrushed = *(int32*)0x943050;
 int32(&CStats::FastestTimes)[CStats::TOTAL_FASTEST_TIMES] = *(int32(*)[CStats::TOTAL_FASTEST_TIMES])*(uintptr*)0x6E9128;
 int32(&CStats::HighestScores)[CStats::TOTAL_HIGHEST_SCORES] = *(int32(*)[CStats::TOTAL_HIGHEST_SCORES]) * (uintptr*)0x8622B0;
 
+void CStats::Init()
+{
+	PeopleKilledByOthers = 0;
+	PeopleKilledByPlayer = 0;
+	RoundsFiredByPlayer = 0;
+	CarsExploded = 0;
+	HelisDestroyed = 0;
+	ProgressMade = 0;
+	KgsOfExplosivesUsed = 0;
+	InstantHitsFiredByPlayer = 0;
+	InstantHitsHitByPlayer = 0;
+	CarsCrushed = 0;
+	HeadsPopped = 0;
+	TimesArrested = 0;
+	TimesDied = 0;
+	DaysPassed = 0;
+	NumberOfUniqueJumpsFound = 0;
+	mmRain = 0;
+	MaximumJumpFlips = 0;
+	MaximumJumpSpins = 0;
+	MaximumJumpDistance = 0;
+	MaximumJumpHeight = 0;
+	BestStuntJump = 0;
+	TotalNumberOfUniqueJumps = 0;
+	Record4x4One = 0;
+	LongestFlightInDodo = 0;
+	Record4x4Two = 0;
+	PassengersDroppedOffWithTaxi = 0;
+	Record4x4Three = 0;
+	MoneyMadeWithTaxi = 0;
+	Record4x4Mayhem = 0;
+	LivesSavedWithAmbulance = 0;
+	ElBurroTime = 0;
+	CriminalsCaught = 0;
+	MissionsGiven = 0;
+	HighestLevelAmbulanceMission = 0;
+	MissionsPassed = 0;
+	FiresExtinguished = 0;
+	DistanceTravelledOnFoot = 0;
+	TimeTakenDefuseMission = 0;
+	NumberKillFrenziesPassed = 0;
+	DistanceTravelledInVehicle = 0;
+	TotalNumberKillFrenzies = 0;
+	TotalNumberMissions = 0;
+	KillsSinceLastCheckpoint = 0;
+	TotalLegitimateKills = 0;
+	for (int i = 0; i < TOTAL_FASTEST_TIMES; i++)
+		FastestTimes[i] = 0;
+	for (int i = 0; i < TOTAL_HIGHEST_SCORES; i++)
+		HighestScores[i] = 0;
+	for (int i = 0; i < NUM_PEDTYPES; i++)
+		PedsKilledOfThisType[i] = 0;
+	IndustrialPassed = 0;
+	CommercialPassed = 0;
+	SuburbanPassed = 0;
+}
+
 void CStats::RegisterFastestTime(int32 index, int32 time)
 {
 	assert(index >= 0 && index < TOTAL_FASTEST_TIMES);
@@ -138,4 +200,229 @@ void CStats::SetTotalNumberMissions(int32 total)
 	TotalNumberMissions = total;
 }
 
-WRAPPER void CStats::Init() { EAXJMP(0x4AAC60); }
\ No newline at end of file
+wchar *CStats::FindCriminalRatingString()
+{
+	int rating = FindCriminalRatingNumber();
+
+	if (rating < 10) return TheText.Get("RATNG1");
+	if (rating < 25) return TheText.Get("RATNG2");
+	if (rating < 70) return TheText.Get("RATNG3");
+	if (rating < 150) return TheText.Get("RATNG4");
+	if (rating < 250) return TheText.Get("RATNG5");
+	if (rating < 450) return TheText.Get("RATNG6");
+	if (rating < 700) return TheText.Get("RATNG7");
+	if (rating < 1000) return TheText.Get("RATNG8");
+	if (rating < 1400) return TheText.Get("RATNG9");
+	if (rating < 1900) return TheText.Get("RATNG10");
+	if (rating < 2500) return TheText.Get("RATNG11");
+	if (rating < 3200) return TheText.Get("RATNG12");
+	if (rating < 4000) return TheText.Get("RATNG13");
+	if (rating < 5000) return TheText.Get("RATNG14");
+	return TheText.Get("RATNG15");
+}
+
+int32 CStats::FindCriminalRatingNumber()
+{
+	int32 rating;
+
+	rating = FiresExtinguished + 10 * HighestLevelAmbulanceMission + CriminalsCaught + LivesSavedWithAmbulance
+		+ 30 * HelisDestroyed + TotalLegitimateKills - 3 * TimesArrested - 3 * TimesDied
+		+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney / 5000;
+	if (rating <= 0) rating = 0;
+
+	if (InstantHitsFiredByPlayer > 100)
+		rating += (float)CStats::InstantHitsHitByPlayer / (float)CStats::InstantHitsFiredByPlayer * 500.0f;
+	if (TotalProgressInGame)
+		rating += (float)CStats::ProgressMade / (float)CStats::TotalProgressInGame * 1000.0f;
+	if (!IndustrialPassed && rating >= 3521)
+		rating = 3521;
+	if (!CommercialPassed && rating >= 4552)
+		rating = 4552;
+	return rating;
+}
+
+void CStats::SaveStats(uint8 *buf, uint32 *size)
+{
+	CheckPointReachedSuccessfully();
+	uint8 *buf_start = buf;
+	*size = sizeof(PeopleKilledByPlayer) +
+		sizeof(PeopleKilledByOthers) +
+		sizeof(CarsExploded) +
+		sizeof(RoundsFiredByPlayer) +
+		sizeof(PedsKilledOfThisType) +
+		sizeof(HelisDestroyed) +
+		sizeof(ProgressMade) +
+		sizeof(TotalProgressInGame) +
+		sizeof(KgsOfExplosivesUsed) +
+		sizeof(InstantHitsFiredByPlayer) +
+		sizeof(InstantHitsHitByPlayer) +
+		sizeof(CarsCrushed) +
+		sizeof(HeadsPopped) +
+		sizeof(TimesArrested) +
+		sizeof(TimesDied) +
+		sizeof(DaysPassed) +
+		sizeof(mmRain) +
+		sizeof(MaximumJumpDistance) +
+		sizeof(MaximumJumpHeight) +
+		sizeof(MaximumJumpFlips) +
+		sizeof(MaximumJumpSpins) +
+		sizeof(BestStuntJump) +
+		sizeof(NumberOfUniqueJumpsFound) +
+		sizeof(TotalNumberOfUniqueJumps) +
+		sizeof(MissionsGiven) +
+		sizeof(MissionsPassed) +
+		sizeof(PassengersDroppedOffWithTaxi) +
+		sizeof(MoneyMadeWithTaxi) +
+		sizeof(IndustrialPassed) +
+		sizeof(CommercialPassed) +
+		sizeof(SuburbanPassed) +
+		sizeof(ElBurroTime) +
+		sizeof(DistanceTravelledOnFoot) +
+		sizeof(DistanceTravelledInVehicle) +
+		sizeof(Record4x4One) +
+		sizeof(Record4x4Two) +
+		sizeof(Record4x4Three) +
+		sizeof(Record4x4Mayhem) +
+		sizeof(LivesSavedWithAmbulance) +
+		sizeof(CriminalsCaught) +
+		sizeof(HighestLevelAmbulanceMission) +
+		sizeof(FiresExtinguished) +
+		sizeof(LongestFlightInDodo) +
+		sizeof(TimeTakenDefuseMission) +
+		sizeof(NumberKillFrenziesPassed) +
+		sizeof(TotalNumberKillFrenzies) +
+		sizeof(TotalNumberMissions) +
+		sizeof(FastestTimes) +
+		sizeof(HighestScores) +
+		sizeof(KillsSinceLastCheckpoint) +
+		sizeof(TotalLegitimateKills) +
+		sizeof(LastMissionPassedName);
+
+#define CopyToBuf(buf, data) memcpy(buf, &data, sizeof(data)); buf += sizeof(data);
+	CopyToBuf(buf, PeopleKilledByPlayer);
+	CopyToBuf(buf, PeopleKilledByOthers);
+	CopyToBuf(buf, CarsExploded);
+	CopyToBuf(buf, RoundsFiredByPlayer);
+	CopyToBuf(buf, PedsKilledOfThisType);
+	CopyToBuf(buf, HelisDestroyed);
+	CopyToBuf(buf, ProgressMade);
+	CopyToBuf(buf, TotalProgressInGame);
+	CopyToBuf(buf, KgsOfExplosivesUsed);
+	CopyToBuf(buf, InstantHitsFiredByPlayer);
+	CopyToBuf(buf, InstantHitsHitByPlayer);
+	CopyToBuf(buf, CarsCrushed);
+	CopyToBuf(buf, HeadsPopped);
+	CopyToBuf(buf, TimesArrested);
+	CopyToBuf(buf, TimesDied);
+	CopyToBuf(buf, DaysPassed);
+	CopyToBuf(buf, mmRain);
+	CopyToBuf(buf, MaximumJumpDistance);
+	CopyToBuf(buf, MaximumJumpHeight);
+	CopyToBuf(buf, MaximumJumpFlips);
+	CopyToBuf(buf, MaximumJumpSpins);
+	CopyToBuf(buf, BestStuntJump);
+	CopyToBuf(buf, NumberOfUniqueJumpsFound);
+	CopyToBuf(buf, TotalNumberOfUniqueJumps);
+	CopyToBuf(buf, MissionsGiven);
+	CopyToBuf(buf, MissionsPassed);
+	CopyToBuf(buf, PassengersDroppedOffWithTaxi);
+	CopyToBuf(buf, MoneyMadeWithTaxi);
+	CopyToBuf(buf, IndustrialPassed);
+	CopyToBuf(buf, CommercialPassed);
+	CopyToBuf(buf, SuburbanPassed);
+	CopyToBuf(buf, ElBurroTime);
+	CopyToBuf(buf, DistanceTravelledOnFoot);
+	CopyToBuf(buf, DistanceTravelledInVehicle);
+	CopyToBuf(buf, Record4x4One);
+	CopyToBuf(buf, Record4x4Two);
+	CopyToBuf(buf, Record4x4Three);
+	CopyToBuf(buf, Record4x4Mayhem);
+	CopyToBuf(buf, LivesSavedWithAmbulance);
+	CopyToBuf(buf, CriminalsCaught);
+	CopyToBuf(buf, HighestLevelAmbulanceMission);
+	CopyToBuf(buf, FiresExtinguished);
+	CopyToBuf(buf, LongestFlightInDodo);
+	CopyToBuf(buf, TimeTakenDefuseMission);
+	CopyToBuf(buf, NumberKillFrenziesPassed);
+	CopyToBuf(buf, TotalNumberKillFrenzies);
+	CopyToBuf(buf, TotalNumberMissions);
+	CopyToBuf(buf, FastestTimes);
+	CopyToBuf(buf, HighestScores);
+	CopyToBuf(buf, KillsSinceLastCheckpoint);
+	CopyToBuf(buf, TotalLegitimateKills);
+	CopyToBuf(buf, LastMissionPassedName);
+
+	assert(buf - buf_start == *size);
+#undef CopyToBuf
+}
+
+void CStats::LoadStats(uint8 *buf, uint32 size)
+{
+	uint8* buf_start = buf;
+
+#define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); buf += sizeof(data);
+
+	CopyFromBuf(buf, PeopleKilledByPlayer);
+	CopyFromBuf(buf, PeopleKilledByOthers);
+	CopyFromBuf(buf, CarsExploded);
+	CopyFromBuf(buf, RoundsFiredByPlayer);
+	CopyFromBuf(buf, PedsKilledOfThisType);
+	CopyFromBuf(buf, HelisDestroyed);
+	CopyFromBuf(buf, ProgressMade);
+	CopyFromBuf(buf, TotalProgressInGame);
+	CopyFromBuf(buf, KgsOfExplosivesUsed);
+	CopyFromBuf(buf, InstantHitsFiredByPlayer);
+	CopyFromBuf(buf, InstantHitsHitByPlayer);
+	CopyFromBuf(buf, CarsCrushed);
+	CopyFromBuf(buf, HeadsPopped);
+	CopyFromBuf(buf, TimesArrested);
+	CopyFromBuf(buf, TimesDied);
+	CopyFromBuf(buf, DaysPassed);
+	CopyFromBuf(buf, mmRain);
+	CopyFromBuf(buf, MaximumJumpDistance);
+	CopyFromBuf(buf, MaximumJumpHeight);
+	CopyFromBuf(buf, MaximumJumpFlips);
+	CopyFromBuf(buf, MaximumJumpSpins);
+	CopyFromBuf(buf, BestStuntJump);
+	CopyFromBuf(buf, NumberOfUniqueJumpsFound);
+	CopyFromBuf(buf, TotalNumberOfUniqueJumps);
+	CopyFromBuf(buf, MissionsGiven);
+	CopyFromBuf(buf, MissionsPassed);
+	CopyFromBuf(buf, PassengersDroppedOffWithTaxi);
+	CopyFromBuf(buf, MoneyMadeWithTaxi);
+	CopyFromBuf(buf, IndustrialPassed);
+	CopyFromBuf(buf, CommercialPassed);
+	CopyFromBuf(buf, SuburbanPassed);
+	CopyFromBuf(buf, ElBurroTime);
+	CopyFromBuf(buf, DistanceTravelledOnFoot);
+	CopyFromBuf(buf, DistanceTravelledInVehicle);
+	CopyFromBuf(buf, Record4x4One);
+	CopyFromBuf(buf, Record4x4Two);
+	CopyFromBuf(buf, Record4x4Three);
+	CopyFromBuf(buf, Record4x4Mayhem);
+	CopyFromBuf(buf, LivesSavedWithAmbulance);
+	CopyFromBuf(buf, CriminalsCaught);
+	CopyFromBuf(buf, HighestLevelAmbulanceMission);
+	CopyFromBuf(buf, FiresExtinguished);
+	CopyFromBuf(buf, LongestFlightInDodo);
+	CopyFromBuf(buf, TimeTakenDefuseMission);
+	CopyFromBuf(buf, NumberKillFrenziesPassed);
+	CopyFromBuf(buf, TotalNumberKillFrenzies);
+	CopyFromBuf(buf, TotalNumberMissions);
+	CopyFromBuf(buf, FastestTimes);
+	CopyFromBuf(buf, HighestScores);
+	CopyFromBuf(buf, KillsSinceLastCheckpoint);
+	CopyFromBuf(buf, TotalLegitimateKills);
+	CopyFromBuf(buf, LastMissionPassedName);
+
+	assert(buf - buf_start == size);
+#undef CopyFromBuf
+}
+
+STARTPATCHES
+	InjectHook(0x48C5A3, CStats::Init, PATCH_JUMP); // CGame::ReInitGameObjectVariables
+	InjectHook(0x4AB3E0, CStats::SaveStats, PATCH_JUMP);
+	InjectHook(0x4AB670, CStats::LoadStats, PATCH_JUMP);
+	InjectHook(0x4AB090, CStats::FindCriminalRatingString, PATCH_JUMP);
+	InjectHook(0x4AB2A0, CStats::FindCriminalRatingNumber, PATCH_JUMP);
+ENDPATCHES
\ No newline at end of file
diff --git a/src/core/Stats.h b/src/core/Stats.h
index 1d220905..ac3259f9 100644
--- a/src/core/Stats.h
+++ b/src/core/Stats.h
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "PedType.h"
+
 class CStats
 {
 public:
@@ -8,14 +10,14 @@ public:
 		TOTAL_HIGHEST_SCORES = 16
 	};
 	static int32 &DaysPassed;
-	static int32 &HeadsPopped;
-	static bool& CommercialPassed;
-	static bool& IndustrialPassed;
-	static bool& SuburbanPassed;
+    static int32 &HeadsPopped;
+	static int32& CommercialPassed;
+	static int32& IndustrialPassed;
+	static int32& SuburbanPassed;
 	static int32 &NumberKillFrenziesPassed;
 	static int32 &PeopleKilledByOthers;
 	static int32 &HelisDestroyed;
-	static int32 *PedsKilledOfThisType;	//[NUM_PEDTYPES]
+	static int32(&PedsKilledOfThisType)[ePedType::NUM_PEDTYPES];
 	static int32 &TimesDied;
 	static int32 &TimesArrested;
 	static int32 &KillsSinceLastCheckpoint;
@@ -50,32 +52,39 @@ public:
 	static int32 &LongestFlightInDodo;
 	static int32 &TimeTakenDefuseMission;
 	static int32 &TotalNumberKillFrenzies;
-	static int32 &TotalNumberMissions;
+    static int32 &TotalNumberMissions;
+    static int32 &RoundsFiredByPlayer;
+    static int32 &KgsOfExplosivesUsed;
+    static int32 &InstantHitsFiredByPlayer;
+    static int32 &InstantHitsHitByPlayer;
+    static int32 &BestTimeBombDefusal;
+    static int32 &mmRain;
+    static int32 &CarsCrushed;
 	static int32(&FastestTimes)[TOTAL_FASTEST_TIMES];
 	static int32(&HighestScores)[TOTAL_HIGHEST_SCORES];
-	static int32 &KgOfExplosivesUsed;
-	static int32 &CarsCrushed;
 
 public:
+	static void Init(void);
 	static void RegisterFastestTime(int32, int32);
 	static void RegisterHighestScore(int32, int32);
-	static void AnotherKillFrenzyPassed();
-	static void AnotherLifeSavedWithAmbulance();
-	static void AnotherCriminalCaught();
-	static void RegisterLevelAmbulanceMission(int32);
-	static void AnotherFireExtinguished();
+	static void RegisterElBurroTime(int32);
 	static void Register4x4OneTime(int32);
 	static void Register4x4TwoTime(int32);
 	static void Register4x4ThreeTime(int32);
 	static void Register4x4MayhemTime(int32);
+	static void AnotherLifeSavedWithAmbulance();
+	static void AnotherCriminalCaught();
+	static void RegisterLevelAmbulanceMission(int32);
+	static void AnotherFireExtinguished();
+	static wchar *FindCriminalRatingString();
 	static void RegisterLongestFlightInDodo(int32);
 	static void RegisterTimeTakenDefuseMission(int32);
+	static void AnotherKillFrenzyPassed();
 	static void SetTotalNumberKillFrenzies(int32);
 	static void SetTotalNumberMissions(int32);
-	static void CheckPointReachedUnsuccessfully() { KillsSinceLastCheckpoint = 0; };
 	static void CheckPointReachedSuccessfully() { TotalLegitimateKills += KillsSinceLastCheckpoint; KillsSinceLastCheckpoint = 0; };
-	static void RegisterElBurroTime(int32);
+	static void CheckPointReachedUnsuccessfully() { KillsSinceLastCheckpoint = 0; };
+	static int32 FindCriminalRatingNumber();
 	static void SaveStats(uint8 *buf, uint32 *size);
-
-	static void Init(void);
+	static void LoadStats(uint8 *buf, uint32 size);
 };
diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp
index 3dcb767a..d00edf51 100644
--- a/src/core/Streaming.cpp
+++ b/src/core/Streaming.cpp
@@ -1247,8 +1247,8 @@ CStreaming::StreamVehiclesAndPeds(void)
 	static int timeBeforeNextLoad = 0;
 	static int modelQualityClass = 0;
 
-	if(CRecordDataForGame::RecordingState == RECORDSTATE_1 ||
-	   CRecordDataForGame::RecordingState == RECORDSTATE_2)
+	if(CRecordDataForGame::IsRecording() ||
+	   CRecordDataForGame::IsPlayingBack())
 		return;
 
 	if(FindPlayerPed()->m_pWanted->AreSwatRequired()){
diff --git a/src/core/Timer.cpp b/src/core/Timer.cpp
index 18d6b6a3..fda862f1 100644
--- a/src/core/Timer.cpp
+++ b/src/core/Timer.cpp
@@ -34,6 +34,10 @@ LARGE_INTEGER &perfSuspendCounter = *(LARGE_INTEGER*)0x62A318;
 //UInt32 suspendDepth;
 uint32 &suspendDepth = *(uint32*)0x62A320;
 
+#ifdef FIX_BUGS
+double frameTime;
+#endif
+
 void CTimer::Initialise(void)
 {
 	debug("Initialising CTimer...\n");
@@ -90,17 +94,21 @@ void CTimer::Update(void)
 		
 		float updInCyclesScaled = updInCycles * ms_fTimeScale;
 		
-		double upd = updInCyclesScaled / (double)_nCyclesPerMS;
+		// We need that real frame time to fix transparent menu bug.
+#ifndef FIX_BUGS
+		double
+#endif
+		frameTime = updInCyclesScaled / (double)_nCyclesPerMS;
 
-		m_snTimeInMillisecondsPauseMode = m_snTimeInMillisecondsPauseMode + upd;
+		m_snTimeInMillisecondsPauseMode = m_snTimeInMillisecondsPauseMode + frameTime;
 		
 		if ( GetIsPaused() )
 			ms_fTimeStep = 0.0f;
 		else
 		{
-			m_snTimeInMilliseconds = m_snTimeInMilliseconds + upd;
-			m_snTimeInMillisecondsNonClipped = m_snTimeInMillisecondsNonClipped + upd;
-			ms_fTimeStep = updInCyclesScaled / (double)_nCyclesPerMS / 20.0f;
+			m_snTimeInMilliseconds = m_snTimeInMilliseconds + frameTime;
+			m_snTimeInMillisecondsNonClipped = m_snTimeInMillisecondsNonClipped + frameTime;
+			ms_fTimeStep = frameTime / 1000.0f * 50.0f;
 		}
 	}
 	else
@@ -109,19 +117,23 @@ void CTimer::Update(void)
 		
 		uint32 updInMs = timer - oldPcTimer;
 		
-		double upd = (double)updInMs * ms_fTimeScale;
+		// We need that real frame time to fix transparent menu bug.
+#ifndef FIX_BUGS
+		double
+#endif
+		frameTime = (double)updInMs * ms_fTimeScale;
 		
 		oldPcTimer = timer;
 		
-		m_snTimeInMillisecondsPauseMode = m_snTimeInMillisecondsPauseMode + upd;
+		m_snTimeInMillisecondsPauseMode = m_snTimeInMillisecondsPauseMode + frameTime;
 															 
 		if ( GetIsPaused() )
 			ms_fTimeStep = 0.0f;
 		else
 		{
-			m_snTimeInMilliseconds = m_snTimeInMilliseconds + upd;
-			m_snTimeInMillisecondsNonClipped = m_snTimeInMillisecondsNonClipped + upd;
-			ms_fTimeStep = upd / 1000.0f * 50.0f;
+			m_snTimeInMilliseconds = m_snTimeInMilliseconds + frameTime;
+			m_snTimeInMillisecondsNonClipped = m_snTimeInMillisecondsNonClipped + frameTime;
+			ms_fTimeStep = frameTime / 1000.0f * 50.0f;
 		}
 	}
 	
@@ -130,7 +142,7 @@ void CTimer::Update(void)
 
 	ms_fTimeStepNonClipped = ms_fTimeStep;
 	
-	if ( CRecordDataForGame::RecordingState != RECORDSTATE_2 )
+	if ( !CRecordDataForGame::IsPlayingBack() )
 	{
 		ms_fTimeStep = min(3.0f, ms_fTimeStep);
 
@@ -138,7 +150,7 @@ void CTimer::Update(void)
 			m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 60;
 	}
   
-	if ( CRecordDataForChase::Status == RECORDSTATE_1 )
+	if ( CRecordDataForChase::IsRecording() )
 	{
 		ms_fTimeStep = 1.0f;
 		m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 16;
diff --git a/src/core/Timer.h b/src/core/Timer.h
index 2498ec8a..a4d674da 100644
--- a/src/core/Timer.h
+++ b/src/core/Timer.h
@@ -21,6 +21,7 @@ public:
 	static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; }
 	static const float &GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
 	static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; }
+	static float GetTimeStepNonClippedInMilliseconds(void) { return ms_fTimeStepNonClipped / 50.0f * 1000.0f; }
 	static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; }
 	static const uint32 &GetFrameCounter(void) { return m_FrameCounter; }
 	static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; }
@@ -52,4 +53,11 @@ public:
 	static void Stop(void);
 	static void StartUserPause(void);
 	static void EndUserPause(void);
+
+	friend bool GenericLoad(void);
+	friend bool GenericSave(int file);
 };
+
+#ifdef FIX_BUGS
+extern double frameTime;
+#endif
diff --git a/src/core/World.cpp b/src/core/World.cpp
index 4a0230ce..d64569b3 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -56,6 +56,8 @@ WRAPPER void CWorld::FindMissionEntitiesIntersectingCube(const CVector&, const C
 WRAPPER void CWorld::ClearCarsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B50E0); }
 WRAPPER void CWorld::ClearPedsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B52B0); }
 WRAPPER void CWorld::CallOffChaseForArea(float, float, float, float) { EAXJMP(0x4B5530); }
+WRAPPER void CWorld::TriggerExplosion(const CVector& a1, float a2, float a3, CEntity *a4, bool a5) { EAXJMP(0x4B1140); }
+WRAPPER void CWorld::SetPedsOnFire(float, float, float, float, CEntity*) { EAXJMP(0x4B3D30); }
 
 void
 CWorld::Initialise()
diff --git a/src/core/World.h b/src/core/World.h
index c4103eb2..07e7889f 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -132,6 +132,7 @@ public:
 	static void SetAllCarsCanBeDamaged(bool);
 	static void ExtinguishAllCarFiresInArea(CVector, float);
 	static void SetCarsOnFire(float, float, float, float, CEntity*);
+	static void SetPedsOnFire(float, float, float, float, CEntity*);
 
 	static void Initialise();
 	static void AddParticles();
@@ -140,6 +141,7 @@ public:
 	static void RepositionCertainDynamicObjects();
 	static void RemoveStaticObjects();
 	static void Process();
+	static void TriggerExplosion(const CVector &, float, float, CEntity*, bool);
 };
 
 extern CColPoint *gaTempSphereColPoints;
diff --git a/src/core/common.h b/src/core/common.h
index b58b93af..7688b182 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -74,9 +74,11 @@ inline uint32 ldb(uint32 p, uint32 s, uint32 w)
 }
 
 
+#ifndef RWLIBS
 // little hack
 extern void **rwengine;
 #define RwEngineInstance (*rwengine)
+#endif
 
 #include "skeleton.h"
 #include "Draw.h"
@@ -84,12 +86,14 @@ extern void **rwengine;
 #define DEFAULT_SCREEN_WIDTH (640)
 #define DEFAULT_SCREEN_HEIGHT (448)
 #define DEFAULT_ASPECT_RATIO (4.0f/3.0f)
+#define DEFAULT_VIEWWINDOW (0.7f)
 
 // game uses maximumWidth/Height, but this probably won't work
 // with RW windowed mode
 #define SCREEN_WIDTH ((float)RsGlobal.width)
 #define SCREEN_HEIGHT ((float)RsGlobal.height)
 #define SCREEN_ASPECT_RATIO (CDraw::GetAspectRatio())
+#define SCREEN_VIEWWINDOW (Tan(DEGTORAD(CDraw::GetFOV() * 0.5f)))
 
 // This scales from PS2 pixel coordinates to the real resolution
 #define SCREEN_STRETCH_X(a)   ((a) * (float) SCREEN_WIDTH / DEFAULT_SCREEN_WIDTH)
@@ -105,10 +109,8 @@ extern void **rwengine;
 
 #ifdef ASPECT_RATIO_SCALE
 #define SCREEN_SCALE_AR(a) ((a) * DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO)
-#define SCREEN_SCALE_AR2(a) ((a) / (DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO))
 #else
 #define SCREEN_SCALE_AR(a) (a)
-#define SCREEN_SCALE_AR2(a) (a)
 #endif
 
 #include "maths.h"
diff --git a/src/core/config.h b/src/core/config.h
index 373fca2f..f7fde579 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -73,9 +73,13 @@ enum Config {
 	NUMCORONAS = 56,
 	NUMPOINTLIGHTS = 32,
 	NUM3DMARKERS = 32,
+	NUMBRIGHTLIGHTS = 32,
+	NUMSHINYTEXTS = 32,
 	NUMMONEYMESSAGES = 16,
 	NUMPICKUPMESSAGES = 16,
 	NUMBULLETTRACES = 16,
+	NUMMBLURSTREAKS = 4,
+	NUMSKIDMARKS = 32,
 
 	NUMONSCREENTIMERENTRIES = 1,
 	NUMRADARBLIPS = 32,
@@ -83,6 +87,7 @@ enum Config {
 	NUMSCRIPTEDPICKUPS = 16,
 	NUMPICKUPS = NUMGENERALPICKUPS + NUMSCRIPTEDPICKUPS,
 	NUMCOLLECTEDPICKUPS = 20,
+	NUMPACMANPICKUPS = 256,
 	NUMEVENTS = 64,
 
 	NUM_CARGENS = 160,
@@ -120,7 +125,11 @@ enum Config {
 	NUM_AUDIO_REFLECTIONS = 5,
 	NUM_SCRIPT_MAX_ENTITIES = 40,
 
-	NUM_GARAGE_STORED_CARS = 6
+	NUM_GARAGE_STORED_CARS = 6,
+
+	NUM_CRANES = 8,
+
+	NUM_EXPLOSIONS = 48,
 };
 
 // We'll use this once we're ready to become independent of the game
@@ -145,6 +154,7 @@ enum Config {
 //#define MASTER
 
 #if defined GTA_PS2
+#	define GTA_PS2_STUFF
 #	define RANDOMSPLASH
 #elif defined GTA_PC
 #	define GTA3_1_1_PATCH
@@ -183,13 +193,17 @@ enum Config {
 // Pad
 #define XINPUT
 #define KANGAROO_CHEAT
-#define REGISTER_START_BUTTON // currently only in menu sadly. resumes the game
+#define REGISTER_START_BUTTON
 
 // Hud, frontend and radar
 #define ASPECT_RATIO_SCALE	// Not just makes everything scale with aspect ratio, also adds support for all aspect ratios
 #define TRIANGULAR_BLIPS	// height indicating triangular radar blips, as in VC
 #define PS2_SAVE_DIALOG		// PS2 style save dialog with transparent black box
 // #define PS2_LIKE_MENU	// An effort to recreate PS2 menu, cycling through tabs, different bg etc.
+#define MENU_MAP			// VC-like menu map. Make sure you have new menu.txd
+#define SCROLLABLE_STATS_PAGE	// only draggable by mouse atm
+#define TRIANGLE_BACK_BUTTON
+// #define CIRCLE_BACK_BUTTON
 
 // Script
 #define USE_DEBUG_SCRIPT_LOADER	// makes game load main_freeroam.scm by default
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 674527f5..f09c2e0a 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -1,6 +1,10 @@
 #include "common.h"
+#include "rpmatfx.h"
+#include "rphanim.h"
+#include "rpskin.h"
 #include "patcher.h"
 #include "main.h"
+#include "CdStream.h"
 #include "General.h"
 #include "RwHelper.h"
 #include "Clouds.h"
@@ -49,12 +53,11 @@
 #include "Frontend.h"
 #include "AnimViewer.h"
 #include "Script.h"
+#include "PathFind.h"
 #include "Debug.h"
 #include "Console.h"
 #include "timebars.h"
-
-#define DEFAULT_VIEWWINDOW (Tan(DEGTORAD(CDraw::GetFOV() * 0.5f)))
-
+#include "GenericGameStorage.h"
 
 GlobalScene &Scene = *(GlobalScene*)0x726768;
 
@@ -68,293 +71,68 @@ char *gString2 = (char*)0x878A40;
 wchar *gUString = (wchar*)0x74B018;
 wchar *gUString2 = (wchar*)0x6EDD70;
 
-bool &b_FoundRecentSavedGameWantToLoad = *(bool*)0x95CDA8;
-
-
-char version_name[64];
 
 float FramesPerSecond = 30.0f;
 
 bool gbPrintShite = false;
 bool &gbModelViewer = *(bool*)0x95CD93;
 
-bool DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
-bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
-void DoRWStuffEndOfFrame(void);
+int32 frameCount;
 
-void RenderScene(void);
-void RenderDebugShit(void);
-void RenderEffects(void);
-void Render2dStuff(void);
-void RenderMenus(void);
-void DoFade(void);
-void Render2dStuffAfterFade(void);
+RwRGBA gColourTop;
 
-CSprite2d *LoadSplash(const char *name);
+bool gameAlreadyInitialised;
 
+float NumberOfChunksLoaded;
+#define TOTALNUMCHUNKS 73.0f
+
+bool g_SlowMode = false;
+char version_name[64];
+
+
+void GameInit(void);
+void SystemInit(void);
+void TheGame(void);
 
 extern void (*DebugMenuProcess)(void);
 extern void (*DebugMenuRender)(void);
 void DebugMenuInit(void);
 void DebugMenuPopulate(void);
 
-void PrintGameVersion();
-
-RwRGBA gColourTop;
 
 void
-InitialiseGame(void)
+ValidateVersion()
 {
-	LoadingScreen(nil, nil, "loadsc0");
-	CGame::Initialise("DATA\\GTA3.DAT");
-}
+	int32 file = CFileMgr::OpenFile("models\\coll\\peds.col", "rb");
+	char buff[128];
 
-#ifndef MASTER
-void
-TheModelViewer(void)
-{
-#ifdef ASPECT_RATIO_SCALE
-	CDraw::SetAspectRatio(CDraw::FindAspectRatio());
-#endif
-	CAnimViewer::Update();
-	CTimer::Update();
-	SetLightsWithTimeOfDayColour(Scene.world);
-	CRenderer::ConstructRenderList();
-	DoRWStuffStartOfFrame(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(),
-		CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(),
-		255);
-
-	CSprite2d::InitPerFrame();
-	CFont::InitPerFrame();
-	DefinedState();
-	CVisibilityPlugins::InitAlphaEntityList();
-	CAnimViewer::Render();
-	Render2dStuff();
-	DoRWStuffEndOfFrame();
-}
-#endif
-
-void
-Idle(void *arg)
-{
-#ifdef ASPECT_RATIO_SCALE
-	CDraw::SetAspectRatio(CDraw::FindAspectRatio());
-#endif
-
-	CTimer::Update();
-
-#ifdef TIMEBARS
-	tbInit();
-#endif
-
-	CSprite2d::InitPerFrame();
-	CFont::InitPerFrame();
-
-	// We're basically merging FrontendIdle and Idle (just like TheGame on PS2)
-#ifdef PS2_SAVE_DIALOG
-	// Only exists on PC FrontendIdle, probably some PS2 bug fix
-	if (FrontEndMenuManager.m_bMenuActive)
-		CSprite2d::SetRecipNearClip();
-	
-	if (FrontEndMenuManager.m_bGameNotLoaded) {
-		CPad::UpdatePads();
-		FrontEndMenuManager.Process();
-	} else {
-		CPointLights::InitPerFrame();
-#ifdef TIMEBARS
-		tbStartTimer(0, "CGame::Process");
-#endif
-		CGame::Process();
-#ifdef TIMEBARS
-		tbEndTimer("CGame::Process");
-		tbStartTimer(0, "DMAudio.Service");
-#endif
-		DMAudio.Service();
-
-#ifdef TIMEBARS
-		tbEndTimer("DMAudio.Service");
-#endif
-	}
-
-	if (RsGlobal.quit)
-		return;
-#else
-	CPointLights::InitPerFrame();
-#ifdef TIMEBARS
-	tbStartTimer(0, "CGame::Process");
-#endif
-	CGame::Process();
-#ifdef TIMEBARS
-	tbEndTimer("CGame::Process");
-	tbStartTimer(0, "DMAudio.Service");
-#endif
-
-	DMAudio.Service();
-
-#ifdef TIMEBARS
-	tbEndTimer("DMAudio.Service");
-#endif
-#endif
-
-	if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){
-		FrontEndMenuManager.m_bStartGameLoading = true;
-		FrontEndMenuManager.m_bLoadingSavedGame = false;
-		return;
-	}
-
-	if(FrontEndMenuManager.m_bStartGameLoading || b_FoundRecentSavedGameWantToLoad)
-		return;
-
-	SetLightsWithTimeOfDayColour(Scene.world);
-
-	if(arg == nil)
-		return;
-
-	if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu) &&
-	   TheCamera.GetScreenFadeStatus() != FADE_2){
-#ifdef GTA_PC
-		if (!FrontEndMenuManager.m_bRenderGameInMenu) {
-			// This is from SA, but it's nice for windowed mode
-			RwV2d pos;
-			pos.x = SCREEN_WIDTH / 2.0f;
-			pos.y = SCREEN_HEIGHT / 2.0f;
-			RsMouseSetPos(&pos);
+	if ( file != -1 )
+	{
+		CFileMgr::Seek(file, 100, SEEK_SET);
+		
+		for ( int i = 0; i < 128; i++ )
+		{
+			CFileMgr::Read(file, &buff[i], sizeof(char));
+			buff[i] -= 23;
+			if ( buff[i] == '\0' )
+				break;
+			CFileMgr::Seek(file, 99, SEEK_CUR);
 		}
-#endif
-#ifdef TIMEBARS
-		tbStartTimer(0, "CnstrRenderList");
-#endif
-		CRenderer::ConstructRenderList();
-#ifdef TIMEBARS
-		tbEndTimer("CnstrRenderList");
-		tbStartTimer(0, "PreRender");
-#endif
-		CRenderer::PreRender();
-#ifdef TIMEBARS
-		tbEndTimer("PreRender");
-#endif
-
-		if(CWeather::LightningFlash && !CCullZones::CamNoRain()){
-			if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255))
-				return;
-		}else{
-			if(!DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(),
-						CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(),
-						255))
-				return;
-		}
-
-		DefinedState();
-
-		// BUG. This has to be done BEFORE RwCameraBeginUpdate
-		RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip());
-		RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
-
-#ifdef TIMEBARS
-		tbStartTimer(0, "RenderScene");
-#endif
-		RenderScene();
-#ifdef TIMEBARS
-		tbEndTimer("RenderScene");
-#endif
-		RenderDebugShit();
-		RenderEffects();
-
-#ifdef TIMEBARS
-		tbStartTimer(0, "RenderMotionBlur");
-#endif
-		if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) &&
-		   TheCamera.m_ScreenReductionPercentage > 0.0f)
-		        TheCamera.SetMotionBlurAlpha(150);
-		TheCamera.RenderMotionBlur();
-#ifdef TIMEBARS
-		tbEndTimer("RenderMotionBlur");
-		tbStartTimer(0, "Render2dStuff");
-#endif
-		Render2dStuff();
-#ifdef TIMEBARS
-		tbEndTimer("Render2dStuff");
-#endif
-	}else{
-		float viewWindow = DEFAULT_VIEWWINDOW;
-#ifdef ASPECT_RATIO_SCALE
-		CameraSize(Scene.camera, nil, viewWindow, SCREEN_ASPECT_RATIO);
-#else
-		CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO);
-#endif
-		CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
-		RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
-		if(!RsCameraBeginUpdate(Scene.camera))
+		
+		if ( !strncmp(buff, "grandtheftauto3", 15) )
+		{
+			strncpy(version_name, &buff[15], 64);
+			CFileMgr::CloseFile(file);
 			return;
+		}
 	}
 
-#ifdef PS2_SAVE_DIALOG
-	if (FrontEndMenuManager.m_bMenuActive)
-		DefinedState();
-#endif
-#ifdef TIMEBARS
-	tbStartTimer(0, "RenderMenus");
-#endif
-	RenderMenus();
-#ifdef TIMEBARS
-	tbEndTimer("RenderMenus");
-	tbStartTimer(0, "DoFade");
-#endif
-	DoFade();
-#ifdef TIMEBARS
-	tbEndTimer("DoFade");
-	tbStartTimer(0, "Render2dStuff-Fade");
-#endif
-	Render2dStuffAfterFade();
-#ifdef TIMEBARS
-	tbEndTimer("Render2dStuff-Fade");
-#endif
-	CCredits::Render();
-
-#ifdef TIMEBARS
-	tbDisplay();
-#endif
-
-	DoRWStuffEndOfFrame();
-
-//	if(g_SlowMode) 
-//		ProcessSlowMode();
-}
-
-void
-FrontendIdle(void)
-{
-#ifdef ASPECT_RATIO_SCALE
-	CDraw::SetAspectRatio(CDraw::FindAspectRatio());
-#endif
-
-	CTimer::Update();
-	CSprite2d::SetRecipNearClip(); // this should be on InitialiseRenderWare according to PS2 asm. seems like a bug fix
-	CSprite2d::InitPerFrame();
-	CFont::InitPerFrame();
-	CPad::UpdatePads();
-	FrontEndMenuManager.Process();
-
-	if(RsGlobal.quit)
-		return;
-
-	float viewWindow = DEFAULT_VIEWWINDOW;
-#ifdef ASPECT_RATIO_SCALE
-	CameraSize(Scene.camera, nil, viewWindow, SCREEN_ASPECT_RATIO);
-#else
-	CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO);
-#endif
-	CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
-	RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
-	if(!RsCameraBeginUpdate(Scene.camera))
-		return;
-
-	DefinedState(); // seems redundant, but breaks resolution change.
-	RenderMenus();
-	DoFade();
-	Render2dStuffAfterFade();
-//	CFont::DrawFonts(); // redundant
-	DoRWStuffEndOfFrame();
+	LoadingScreen("Invalid version", NULL, NULL);
+	
+	while(true)
+	{
+		;
+	}
 }
 
 bool
@@ -363,7 +141,7 @@ DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomR
 	CRGBA TopColor(TopRed, TopGreen, TopBlue, Alpha);
 	CRGBA BottomColor(BottomRed, BottomGreen, BottomBlue, Alpha);
 
-	CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO);
+	CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
 	CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
 	RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
 
@@ -381,7 +159,7 @@ DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomR
 bool
 DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha)
 {
-	CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO);
+	CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
 	CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
 	RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
 
@@ -394,17 +172,6 @@ DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16
 	return true;
 }
 
-void
-DoRWStuffEndOfFrame(void)
-{
-	CDebug::DisplayScreenStrings();	// custom
-	CDebug::DebugDisplayTextBuffer();
-	FlushObrsPrintfs();
-	RwCameraEndUpdate(Scene.camera);
-	RsCameraShowRaster(Scene.camera);
-}
-
-
 // This is certainly a very useful function
 void
 DoRWRenderHorizon(void)
@@ -412,127 +179,6 @@ DoRWRenderHorizon(void)
 	CClouds::RenderHorizon();
 }
 
-void
-RenderScene(void)
-{
-	CClouds::Render();
-	DoRWRenderHorizon();
-	CRenderer::RenderRoads();
-	CCoronas::RenderReflections();
-	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
-	CRenderer::RenderEverythingBarRoads();
-	CRenderer::RenderBoats();
-	DefinedState();
-	CWaterLevel::RenderWater();
-	CRenderer::RenderFadingInEntities();
-	CRenderer::RenderVehiclesButNotBoats();
-	CWeather::RenderRainStreaks();
-}
-
-void
-RenderDebugShit(void)
-{
-	CTheScripts::RenderTheScriptDebugLines();
-	if(gbShowCollisionLines)
-		CRenderer::RenderCollisionLines();
-}
-
-void
-RenderEffects(void)
-{
-	CGlass::Render();
-	CWaterCannons::Render();
-	CSpecialFX::Render();
-	CShadows::RenderStaticShadows();
-	CShadows::RenderStoredShadows();
-	CSkidmarks::Render();
-	CAntennas::Render();
-	CRubbish::Render();
-	CCoronas::Render();
-	CParticle::Render();
-	CPacManPickups::Render();
-	CWeaponEffects::Render();
-	CPointLights::RenderFogEffect();
-	CMovingThings::Render();
-	CRenderer::RenderFirstPersonVehicle();
-}
-
-void
-Render2dStuff(void)
-{
-	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
-	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
-
-	CReplay::Display();
-	CPickups::RenderPickUpText();
-
-	if(TheCamera.m_WideScreenOn)
-		TheCamera.DrawBordersForWideScreen();
-
-	CPed *player = FindPlayerPed();
-	int weaponType = 0;
-	if(player)
-		weaponType = player->GetWeapon()->m_eWeaponType;
-
-	bool firstPersonWeapon = false;
-	int cammode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
-	if(cammode == CCam::MODE_SNIPER ||
-	   cammode == CCam::MODE_SNIPER_RUNABOUT ||
-	   cammode == CCam::MODE_ROCKETLAUNCHER ||
-	   cammode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT)
-		firstPersonWeapon = true;
-
-	// Draw black border for sniper and rocket launcher
-	if((weaponType == WEAPONTYPE_SNIPERRIFLE || weaponType == WEAPONTYPE_ROCKETLAUNCHER) && firstPersonWeapon){
-		CRGBA black(0, 0, 0, 255);
-
-		// top and bottom strips
-		if (weaponType == WEAPONTYPE_ROCKETLAUNCHER) {
-			CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(180)), black);
-			CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(170), SCREEN_WIDTH, SCREEN_HEIGHT), black);
-		}
-		else {
-			CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(210)), black);
-			CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(210), SCREEN_WIDTH, SCREEN_HEIGHT), black);
-		}
-		CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH / 2 - SCREEN_SCALE_X(210), SCREEN_HEIGHT), black);
-		CSprite2d::DrawRect(CRect(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(210), 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), black);
-	}
-
-	MusicManager.DisplayRadioStationName();
-	TheConsole.Display();
-/*
-	if(CSceneEdit::m_bEditOn)
-		CSceneEdit::Draw();
-	else
-*/
-		CHud::Draw();
-	CUserDisplay::OnscnTimer.ProcessForDisplay();
-	CMessages::Display();
-	CDarkel::DrawMessages();
-	CGarages::PrintMessages();
-	CPad::PrintErrorMessage();
-	CFont::DrawFonts();
-
-	DebugMenuRender();
-}
-
-void
-RenderMenus(void)
-{
-	if(FrontEndMenuManager.m_bMenuActive)
-		FrontEndMenuManager.DrawFrontEnd();
-}
-
-bool &JustLoadedDontFadeInYet = *(bool*)0x95CDB4;
-bool &StillToFadeOut = *(bool*)0x95CD99;
-uint32 &TimeStartedCountingForFade = *(uint32*)0x9430EC;
-uint32 &TimeToStayFadedBeforeFadeOut = *(uint32*)0x611564;
-
 void
 DoFade(void)
 {
@@ -613,6 +259,391 @@ DoFade(void)
 	}
 }
 
+void
+DoRWStuffEndOfFrame(void)
+{
+	CDebug::DisplayScreenStrings();	// custom
+	CDebug::DebugDisplayTextBuffer();
+	FlushObrsPrintfs();
+	RwCameraEndUpdate(Scene.camera);
+	RsCameraShowRaster(Scene.camera);
+}
+
+static RwBool 
+PluginAttach(void)
+{
+	if( !RpWorldPluginAttach() )
+	{
+		printf("Couldn't attach world plugin\n");
+		
+		return FALSE;
+	}
+	
+	if( !RpSkinPluginAttach() )
+	{
+		printf("Couldn't attach RpSkin plugin\n");
+		
+		return FALSE;
+	}
+	
+	if( !RpHAnimPluginAttach() )
+	{
+		printf("Couldn't attach RpHAnim plugin\n");
+		
+		return FALSE;
+	}
+	
+	if( !NodeNamePluginAttach() )
+	{
+		printf("Couldn't attach node name plugin\n");
+		
+		return FALSE;
+	}
+	
+	if( !CVisibilityPlugins::PluginAttach() )
+	{
+		printf("Couldn't attach visibility plugins\n");
+		
+		return FALSE;
+	}
+	
+	if( !RpAnimBlendPluginAttach() )
+	{
+		printf("Couldn't attach RpAnimBlend plugin\n");
+		
+		return FALSE;
+	}
+	
+	if( !RpMatFXPluginAttach() )
+	{
+		printf("Couldn't attach RpMatFX plugin\n");
+		
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static RwBool 
+Initialise3D(void *param)
+{
+	if (RsRwInitialise(param))
+	{
+		//
+		DebugMenuInit();
+		DebugMenuPopulate();
+		//
+
+		return CGame::InitialiseRenderWare();
+	}
+
+	return (FALSE);
+}
+
+static void 
+Terminate3D(void)
+{
+	CGame::ShutdownRenderWare();
+	
+	RsRwTerminate();
+
+	return;
+}
+
+CSprite2d splash;
+int splashTxdId = -1;
+
+CSprite2d*
+LoadSplash(const char *name)
+{
+	RwTexDictionary *txd;
+	char filename[140];
+	RwTexture *tex = nil;
+
+	if(name == nil)
+		return &splash;
+	if(splashTxdId == -1)
+		splashTxdId = CTxdStore::AddTxdSlot("splash");
+
+	txd = CTxdStore::GetSlot(splashTxdId)->texDict;
+	if(txd)
+		tex = RwTexDictionaryFindNamedTexture(txd, name);
+	// if texture is found, splash was already set up below
+
+	if(tex == nil){
+		CFileMgr::SetDir("TXD\\");
+		sprintf(filename, "%s.txd", name);
+		if(splash.m_pTexture)
+			splash.Delete();
+		if(txd)
+			CTxdStore::RemoveTxd(splashTxdId);
+		CTxdStore::LoadTxd(splashTxdId, filename);
+		CTxdStore::AddRef(splashTxdId);
+		CTxdStore::PushCurrentTxd();
+		CTxdStore::SetCurrentTxd(splashTxdId);
+		splash.SetTexture(name);
+		CTxdStore::PopCurrentTxd();
+		CFileMgr::SetDir("");
+	}
+
+	return &splash;
+}
+
+void
+DestroySplashScreen(void)
+{
+	splash.Delete();
+	if(splashTxdId != -1)
+		CTxdStore::RemoveTxdSlot(splashTxdId);
+	splashTxdId = -1;
+}
+
+char*
+GetRandomSplashScreen(void)
+{
+	int index;
+	static int index2 = 0;
+	static char splashName[128];
+	static int splashIndex[24] = {
+		25, 22, 4, 13,
+		1, 21, 14, 16,
+		10, 12, 5, 9,
+		11, 18, 3, 2,
+		19, 23, 7, 17,
+		15, 6, 8, 20
+	};
+
+	index = splashIndex[4*index2 + CGeneral::GetRandomNumberInRange(0, 3)];
+	index2++;
+	if(index2 == 6)
+		index2 = 0;
+	sprintf(splashName, "loadsc%d", index);
+	return splashName;
+}
+
+char*
+GetLevelSplashScreen(int level)
+{
+	static char *splashScreens[4] = {
+		nil,
+		"splash1",
+		"splash2",
+		"splash3",
+	};
+
+	return splashScreens[level];
+}
+
+void
+ResetLoadingScreenBar()
+{
+	NumberOfChunksLoaded = 0.0f;
+}
+
+// TODO: compare with PS2
+void
+LoadingScreen(const char *str1, const char *str2, const char *splashscreen)
+{
+	CSprite2d *splash;
+
+#ifndef RANDOMSPLASH
+	if(CGame::frenchGame || CGame::germanGame || !CGame::nastyGame)
+		splashscreen = "mainsc2";
+	else
+		splashscreen = "mainsc1";
+#endif
+
+	splash = LoadSplash(splashscreen);
+
+#ifndef GTA_PS2
+	if(RsGlobal.quit)
+		return;
+#endif
+
+	if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)){
+		CSprite2d::SetRecipNearClip();
+		CSprite2d::InitPerFrame();
+		CFont::InitPerFrame();
+		DefinedState();
+		RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+		splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
+
+		if(str1){
+			NumberOfChunksLoaded += 1;
+
+			float hpos = SCREEN_SCALE_X(40);
+			float length = SCREEN_WIDTH - SCREEN_SCALE_X(100);
+			float vpos = SCREEN_HEIGHT - SCREEN_SCALE_Y(13);
+			float height = SCREEN_SCALE_Y(7);
+			CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(40, 53, 68, 255));
+
+			length *= NumberOfChunksLoaded/TOTALNUMCHUNKS;
+			CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(81, 106, 137, 255));
+
+			// this is done by the game but is unused
+			CFont::SetScale(SCREEN_SCALE_X(2), SCREEN_SCALE_Y(2));
+			CFont::SetPropOn();
+			CFont::SetRightJustifyOn();
+			CFont::SetFontStyle(FONT_HEADING);
+
+#ifdef CHATTYSPLASH
+			// my attempt
+			static wchar tmpstr[80];
+			float yscale = SCREEN_SCALE_Y(0.9f);
+			vpos -= 45*yscale;
+			CFont::SetScale(SCREEN_SCALE_X(0.75f), yscale);
+			CFont::SetPropOn();
+			CFont::SetRightJustifyOff();
+			CFont::SetFontStyle(FONT_BANK);
+			CFont::SetColor(CRGBA(255, 255, 255, 255));
+			AsciiToUnicode(str1, tmpstr);
+			CFont::PrintString(hpos, vpos, tmpstr);
+			vpos += 22*yscale;
+			AsciiToUnicode(str2, tmpstr);
+			CFont::PrintString(hpos, vpos, tmpstr);
+#endif
+		}
+
+		CFont::DrawFonts();
+ 		DoRWStuffEndOfFrame();
+	}
+}
+
+void
+LoadingIslandScreen(const char *levelName)
+{
+	CSprite2d *splash;
+	wchar *name;
+	char str[100];
+	wchar wstr[80];
+	CRGBA col;
+
+	splash = LoadSplash(nil);
+	name = TheText.Get(levelName);
+	if(!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
+		return;
+
+	CSprite2d::SetRecipNearClip();
+	CSprite2d::InitPerFrame();
+	CFont::InitPerFrame();
+	DefinedState();
+	col = CRGBA(255, 255, 255, 255);
+	splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), col, col, col, col);
+	CFont::SetBackgroundOff();
+	CFont::SetScale(1.5f, 1.5f);
+	CFont::SetPropOn();
+	CFont::SetRightJustifyOn();
+	CFont::SetRightJustifyWrap(150.0f);
+	CFont::SetFontStyle(FONT_HEADING);
+	sprintf(str, "WELCOME TO");
+	AsciiToUnicode(str, wstr);
+	CFont::SetDropColor(CRGBA(0, 0, 0, 255));
+	CFont::SetDropShadowPosition(3);
+	CFont::SetColor(CRGBA(243, 237, 71, 255));
+	CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
+	CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME"));
+	TextCopy(wstr, name);
+	TheText.UpperCase(wstr);
+	CFont::SetColor(CRGBA(243, 237, 71, 255));
+	CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
+	CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr);
+	CFont::DrawFonts();
+	DoRWStuffEndOfFrame();
+}
+
+void
+ProcessSlowMode(void)
+{  
+	int16 lX = CPad::GetPad(0)->NewState.LeftStickX;
+	int16 lY = CPad::GetPad(0)->NewState.LeftStickY;
+	int16 rX = CPad::GetPad(0)->NewState.RightStickX;
+	int16 rY = CPad::GetPad(0)->NewState.RightStickY;
+	int16 L1 = CPad::GetPad(0)->NewState.LeftShoulder1;
+	int16 L2 = CPad::GetPad(0)->NewState.LeftShoulder2;
+	int16 R1 = CPad::GetPad(0)->NewState.RightShoulder1;
+	int16 R2 = CPad::GetPad(0)->NewState.RightShoulder2;
+	int16 up = CPad::GetPad(0)->NewState.DPadUp;
+	int16 down = CPad::GetPad(0)->NewState.DPadDown;
+	int16 left = CPad::GetPad(0)->NewState.DPadLeft;
+	int16 right = CPad::GetPad(0)->NewState.DPadRight;
+	int16 start = CPad::GetPad(0)->NewState.Start;
+	int16 select = CPad::GetPad(0)->NewState.Select;
+	int16 square = CPad::GetPad(0)->NewState.Square;
+	int16 triangle = CPad::GetPad(0)->NewState.Triangle;
+	int16 cross = CPad::GetPad(0)->NewState.Cross;
+	int16 circle = CPad::GetPad(0)->NewState.Circle;
+	int16 L3 = CPad::GetPad(0)->NewState.LeftShock;
+	int16 R3 = CPad::GetPad(0)->NewState.RightShock;
+	int16 networktalk = CPad::GetPad(0)->NewState.NetworkTalk;
+	int16 stop = true;
+	
+	do
+	{
+		if ( CPad::GetPad(1)->GetLeftShoulder1JustDown() || CPad::GetPad(1)->GetRightShoulder1() )
+			break;
+		
+		if ( stop )
+		{
+			CTimer::Stop();
+			stop = false;
+		}
+		
+		CPad::UpdatePads();
+		
+		RwCameraBeginUpdate(Scene.camera);
+		RwCameraEndUpdate(Scene.camera);
+		
+		if ( CPad::GetPad(1)->GetLeftShoulder1JustDown() || CPad::GetPad(1)->GetRightShoulder1() )
+			break;
+	
+	} while (!CPad::GetPad(1)->GetRightShoulder1());
+	
+	
+	CPad::GetPad(0)->OldState.LeftStickX = lX;
+	CPad::GetPad(0)->OldState.LeftStickY = lY;
+	CPad::GetPad(0)->OldState.RightStickX = rX;
+	CPad::GetPad(0)->OldState.RightStickY = rY;
+	CPad::GetPad(0)->OldState.LeftShoulder1 = L1;
+	CPad::GetPad(0)->OldState.LeftShoulder2 = L2;
+	CPad::GetPad(0)->OldState.RightShoulder1 = R1;
+	CPad::GetPad(0)->OldState.RightShoulder2 = R2;
+	CPad::GetPad(0)->OldState.DPadUp = up;
+	CPad::GetPad(0)->OldState.DPadDown = down;
+	CPad::GetPad(0)->OldState.DPadLeft = left;
+	CPad::GetPad(0)->OldState.DPadRight = right;
+	CPad::GetPad(0)->OldState.Start = start;
+	CPad::GetPad(0)->OldState.Select = select;
+	CPad::GetPad(0)->OldState.Square = square;
+	CPad::GetPad(0)->OldState.Triangle = triangle;
+	CPad::GetPad(0)->OldState.Cross = cross;
+	CPad::GetPad(0)->OldState.Circle = circle;
+	CPad::GetPad(0)->OldState.LeftShock = L3;
+	CPad::GetPad(0)->OldState.RightShock = R3;
+	CPad::GetPad(0)->OldState.NetworkTalk = networktalk;
+	CPad::GetPad(0)->NewState.LeftStickX = lX;
+	CPad::GetPad(0)->NewState.LeftStickY = lY;
+	CPad::GetPad(0)->NewState.RightStickX = rX;
+	CPad::GetPad(0)->NewState.RightStickY = rY;
+	CPad::GetPad(0)->NewState.LeftShoulder1 = L1;
+	CPad::GetPad(0)->NewState.LeftShoulder2 = L2;
+	CPad::GetPad(0)->NewState.RightShoulder1 = R1;
+	CPad::GetPad(0)->NewState.RightShoulder2 = R2;
+	CPad::GetPad(0)->NewState.DPadUp = up;
+	CPad::GetPad(0)->NewState.DPadDown = down;
+	CPad::GetPad(0)->NewState.DPadLeft = left;
+	CPad::GetPad(0)->NewState.DPadRight = right;
+	CPad::GetPad(0)->NewState.Start = start;
+	CPad::GetPad(0)->NewState.Select = select;
+	CPad::GetPad(0)->NewState.Square = square;
+	CPad::GetPad(0)->NewState.Triangle = triangle;
+	CPad::GetPad(0)->NewState.Cross = cross;
+	CPad::GetPad(0)->NewState.Circle = circle;
+	CPad::GetPad(0)->NewState.LeftShock = L3;
+	CPad::GetPad(0)->NewState.RightShock = R3;
+	CPad::GetPad(0)->NewState.NetworkTalk = networktalk;
+}
+
+
 float FramesPerSecondCounter;
 int32 FrameSamples;
 
@@ -736,309 +767,372 @@ DisplayGameDebugText()
 }
 #endif
 
+void
+RenderScene(void)
+{
+	CClouds::Render();
+	DoRWRenderHorizon();
+	CRenderer::RenderRoads();
+	CCoronas::RenderReflections();
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+	CRenderer::RenderEverythingBarRoads();
+	CRenderer::RenderBoats();
+	DefinedState();
+	CWaterLevel::RenderWater();
+	CRenderer::RenderFadingInEntities();
+	CRenderer::RenderVehiclesButNotBoats();
+	CWeather::RenderRainStreaks();
+}
+
+void
+RenderDebugShit(void)
+{
+	CTheScripts::RenderTheScriptDebugLines();
+#ifndef FINAL
+	if(gbShowCollisionLines)
+		CRenderer::RenderCollisionLines();
+	ThePaths.DisplayPathData();
+#endif
+}
+
+void
+RenderEffects(void)
+{
+	CGlass::Render();
+	CWaterCannons::Render();
+	CSpecialFX::Render();
+	CShadows::RenderStaticShadows();
+	CShadows::RenderStoredShadows();
+	CSkidmarks::Render();
+	CAntennas::Render();
+	CRubbish::Render();
+	CCoronas::Render();
+	CParticle::Render();
+	CPacManPickups::Render();
+	CWeaponEffects::Render();
+	CPointLights::RenderFogEffect();
+	CMovingThings::Render();
+	CRenderer::RenderFirstPersonVehicle();
+}
+
+void
+Render2dStuff(void)
+{
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
+
+	CReplay::Display();
+	CPickups::RenderPickUpText();
+
+	if(TheCamera.m_WideScreenOn)
+		TheCamera.DrawBordersForWideScreen();
+
+	CPed *player = FindPlayerPed();
+	int weaponType = 0;
+	if(player)
+		weaponType = player->GetWeapon()->m_eWeaponType;
+
+	bool firstPersonWeapon = false;
+	int cammode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+	if(cammode == CCam::MODE_SNIPER ||
+	   cammode == CCam::MODE_SNIPER_RUNABOUT ||
+	   cammode == CCam::MODE_ROCKETLAUNCHER ||
+	   cammode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT)
+		firstPersonWeapon = true;
+
+	// Draw black border for sniper and rocket launcher
+	if((weaponType == WEAPONTYPE_SNIPERRIFLE || weaponType == WEAPONTYPE_ROCKETLAUNCHER) && firstPersonWeapon){
+		CRGBA black(0, 0, 0, 255);
+
+		// top and bottom strips
+		if (weaponType == WEAPONTYPE_ROCKETLAUNCHER) {
+			CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(180)), black);
+			CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(170), SCREEN_WIDTH, SCREEN_HEIGHT), black);
+		}
+		else {
+			CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(210)), black);
+			CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(210), SCREEN_WIDTH, SCREEN_HEIGHT), black);
+		}
+		CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH / 2 - SCREEN_SCALE_X(210), SCREEN_HEIGHT), black);
+		CSprite2d::DrawRect(CRect(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(210), 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), black);
+	}
+
+	MusicManager.DisplayRadioStationName();
+	TheConsole.Display();
+/*
+	if(CSceneEdit::m_bEditOn)
+		CSceneEdit::Draw();
+	else
+*/
+		CHud::Draw();
+	CUserDisplay::OnscnTimer.ProcessForDisplay();
+	CMessages::Display();
+	CDarkel::DrawMessages();
+	CGarages::PrintMessages();
+	CPad::PrintErrorMessage();
+	CFont::DrawFonts();
+
+	DebugMenuRender();
+}
+
+void
+RenderMenus(void)
+{
+#ifdef PS2
+	if (FrontEndMenuManager.m_bWantToDraw)
+	{
+		gMainHeap.PushMemId(_TODOCONST(17));
+		FrontEndMenuManager.DrawFrontEnd();
+		gMainHeap.PopMemId();
+	}
+#else
+	if(FrontEndMenuManager.m_bMenuActive)
+		FrontEndMenuManager.DrawFrontEnd();
+#endif
+}
+
 void
 Render2dStuffAfterFade(void)
 {
 #ifndef MASTER
 	DisplayGameDebugText();
-	//PrintGameVersion();
 #endif
 
 	CHud::DrawAfterFade();
 	CFont::DrawFonts();
 }
 
-CSprite2d splash;
-int splashTxdId = -1;
-
-CSprite2d*
-LoadSplash(const char *name)
-{
-	RwTexDictionary *txd;
-	char filename[140];
-	RwTexture *tex = nil;
-
-	if(name == nil)
-		return &splash;
-	if(splashTxdId == -1)
-		splashTxdId = CTxdStore::AddTxdSlot("splash");
-
-	txd = CTxdStore::GetSlot(splashTxdId)->texDict;
-	if(txd)
-		tex = RwTexDictionaryFindNamedTexture(txd, name);
-	// if texture is found, splash was already set up below
-
-	if(tex == nil){
-		CFileMgr::SetDir("TXD\\");
-		sprintf(filename, "%s.txd", name);
-		if(splash.m_pTexture)
-			splash.Delete();
-		if(txd)
-			CTxdStore::RemoveTxd(splashTxdId);
-		CTxdStore::LoadTxd(splashTxdId, filename);
-		CTxdStore::AddRef(splashTxdId);
-		CTxdStore::PushCurrentTxd();
-		CTxdStore::SetCurrentTxd(splashTxdId);
-		splash.SetTexture(name);
-		CTxdStore::PopCurrentTxd();
-		CFileMgr::SetDir("");
-	}
-
-	return &splash;
-}
-
 void
-DestroySplashScreen(void)
+Idle(void *arg)
 {
-	splash.Delete();
-	if(splashTxdId != -1)
-		CTxdStore::RemoveTxdSlot(splashTxdId);
-	splashTxdId = -1;
-}
-
-float NumberOfChunksLoaded;
-#define TOTALNUMCHUNKS 73.0f
-
-void
-ResetLoadingScreenBar()
-{
-	NumberOfChunksLoaded = 0.0f;
-}
-
-// TODO: compare with PS2
-void
-LoadingScreen(const char *str1, const char *str2, const char *splashscreen)
-{
-	CSprite2d *splash;
-
-#ifndef RANDOMSPLASH
-	if(CGame::frenchGame || CGame::germanGame || !CGame::nastyGame)
-		splashscreen = "mainsc2";
-	else
-		splashscreen = "mainsc1";
+#ifdef ASPECT_RATIO_SCALE
+	CDraw::SetAspectRatio(CDraw::FindAspectRatio());
 #endif
 
-	splash = LoadSplash(splashscreen);
+	CTimer::Update();
+
+#ifdef TIMEBARS
+	tbInit();
+#endif
+
+	CSprite2d::InitPerFrame();
+	CFont::InitPerFrame();
+
+	// We're basically merging FrontendIdle and Idle (just like TheGame on PS2)
+#ifdef PS2_SAVE_DIALOG
+	// Only exists on PC FrontendIdle, probably some PS2 bug fix
+	if (FrontEndMenuManager.m_bMenuActive)
+		CSprite2d::SetRecipNearClip();
+	
+	if (FrontEndMenuManager.m_bGameNotLoaded) {
+		CPad::UpdatePads();
+		FrontEndMenuManager.Process();
+	} else {
+		CPointLights::InitPerFrame();
+#ifdef TIMEBARS
+		tbStartTimer(0, "CGame::Process");
+#endif
+		CGame::Process();
+#ifdef TIMEBARS
+		tbEndTimer("CGame::Process");
+		tbStartTimer(0, "DMAudio.Service");
+#endif
+		DMAudio.Service();
+
+#ifdef TIMEBARS
+		tbEndTimer("DMAudio.Service");
+#endif
+	}
+
+	if (RsGlobal.quit)
+		return;
+#else
+	CPointLights::InitPerFrame();
+#ifdef TIMEBARS
+	tbStartTimer(0, "CGame::Process");
+#endif
+	CGame::Process();
+#ifdef TIMEBARS
+	tbEndTimer("CGame::Process");
+	tbStartTimer(0, "DMAudio.Service");
+#endif
+
+	DMAudio.Service();
+
+#ifdef TIMEBARS
+	tbEndTimer("DMAudio.Service");
+#endif
+#endif
+
+	if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){
+		FrontEndMenuManager.m_bWantToRestart = true;
+		FrontEndMenuManager.m_bWantToLoad = false;
+		return;
+	}
+
+	if(FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad)
+		return;
+
+	SetLightsWithTimeOfDayColour(Scene.world);
+
+	if(arg == nil)
+		return;
+
+	if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu) &&
+	   TheCamera.GetScreenFadeStatus() != FADE_2)
+	{
+#ifdef GTA_PC
+		if (!FrontEndMenuManager.m_bRenderGameInMenu) {
+			// This is from SA, but it's nice for windowed mode
+			RwV2d pos;
+			pos.x = SCREEN_WIDTH / 2.0f;
+			pos.y = SCREEN_HEIGHT / 2.0f;
+			RsMouseSetPos(&pos);
+		}
+#endif
+#ifdef TIMEBARS
+		tbStartTimer(0, "CnstrRenderList");
+#endif
+		CRenderer::ConstructRenderList();
+#ifdef TIMEBARS
+		tbEndTimer("CnstrRenderList");
+		tbStartTimer(0, "PreRender");
+#endif
+		CRenderer::PreRender();
+#ifdef TIMEBARS
+		tbEndTimer("PreRender");
+#endif
+
+		if(CWeather::LightningFlash && !CCullZones::CamNoRain()){
+			if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255))
+				return;
+		}else{
+			if(!DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(),
+						CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(),
+						255))
+				return;
+		}
+
+		DefinedState();
+
+		// BUG. This has to be done BEFORE RwCameraBeginUpdate
+		RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip());
+		RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
+
+#ifdef TIMEBARS
+		tbStartTimer(0, "RenderScene");
+#endif
+		RenderScene();
+#ifdef TIMEBARS
+		tbEndTimer("RenderScene");
+#endif
+		RenderDebugShit();
+		RenderEffects();
+
+#ifdef TIMEBARS
+		tbStartTimer(0, "RenderMotionBlur");
+#endif
+		if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) &&
+		   TheCamera.m_ScreenReductionPercentage > 0.0f)
+		        TheCamera.SetMotionBlurAlpha(150);
+		TheCamera.RenderMotionBlur();
+#ifdef TIMEBARS
+		tbEndTimer("RenderMotionBlur");
+		tbStartTimer(0, "Render2dStuff");
+#endif
+		Render2dStuff();
+#ifdef TIMEBARS
+		tbEndTimer("Render2dStuff");
+#endif
+	}else{
+#ifdef ASPECT_RATIO_SCALE
+		CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
+#else
+		CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
+#endif
+		CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
+		RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
+		if(!RsCameraBeginUpdate(Scene.camera))
+			return;
+	}
+
+#ifdef PS2_SAVE_DIALOG
+	if (FrontEndMenuManager.m_bMenuActive)
+		DefinedState();
+#endif
+#ifdef TIMEBARS
+	tbStartTimer(0, "RenderMenus");
+#endif
+	RenderMenus();
+#ifdef TIMEBARS
+	tbEndTimer("RenderMenus");
+	tbStartTimer(0, "DoFade");
+#endif
+	DoFade();
+#ifdef TIMEBARS
+	tbEndTimer("DoFade");
+	tbStartTimer(0, "Render2dStuff-Fade");
+#endif
+	Render2dStuffAfterFade();
+#ifdef TIMEBARS
+	tbEndTimer("Render2dStuff-Fade");
+#endif
+	CCredits::Render();
+
+#ifdef TIMEBARS
+	tbDisplay();
+#endif
+
+	DoRWStuffEndOfFrame();
+
+	if(g_SlowMode) 
+		ProcessSlowMode();
+}
+
+void
+FrontendIdle(void)
+{
+#ifdef ASPECT_RATIO_SCALE
+	CDraw::SetAspectRatio(CDraw::FindAspectRatio());
+#endif
+
+	CTimer::Update();
+	CSprite2d::SetRecipNearClip(); // this should be on InitialiseRenderWare according to PS2 asm. seems like a bug fix
+	CSprite2d::InitPerFrame();
+	CFont::InitPerFrame();
+	CPad::UpdatePads();
+	FrontEndMenuManager.Process();
 
 	if(RsGlobal.quit)
 		return;
 
-	if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)){
-		CSprite2d::SetRecipNearClip();
-		CSprite2d::InitPerFrame();
-		CFont::InitPerFrame();
-		DefinedState();
-		RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
-		splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
-
-		if(str1){
-			NumberOfChunksLoaded += 1;
-
-			float hpos = SCREEN_SCALE_X(40);
-			float length = SCREEN_WIDTH - SCREEN_SCALE_X(100);
-			float vpos = SCREEN_HEIGHT - SCREEN_SCALE_Y(13);
-			float height = SCREEN_SCALE_Y(7);
-			CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(40, 53, 68, 255));
-
-			length *= NumberOfChunksLoaded/TOTALNUMCHUNKS;
-			CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(81, 106, 137, 255));
-
-			// this is done by the game but is unused
-			CFont::SetScale(SCREEN_SCALE_X(2), SCREEN_SCALE_Y(2));
-			CFont::SetPropOn();
-			CFont::SetRightJustifyOn();
-			CFont::SetFontStyle(FONT_HEADING);
-
-#ifdef CHATTYSPLASH
-			// my attempt
-			static wchar tmpstr[80];
-			float yscale = SCREEN_SCALE_Y(0.9f);
-			vpos -= 45*yscale;
-			CFont::SetScale(SCREEN_SCALE_X(0.75f), yscale);
-			CFont::SetPropOn();
-			CFont::SetRightJustifyOff();
-			CFont::SetFontStyle(FONT_BANK);
-			CFont::SetColor(CRGBA(255, 255, 255, 255));
-			AsciiToUnicode(str1, tmpstr);
-			CFont::PrintString(hpos, vpos, tmpstr);
-			vpos += 22*yscale;
-			AsciiToUnicode(str2, tmpstr);
-			CFont::PrintString(hpos, vpos, tmpstr);
+#ifdef ASPECT_RATIO_SCALE
+	CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
+#else
+	CameraSize(Scene.camera, nil, SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
 #endif
-		}
-
-		CFont::DrawFonts();
- 		DoRWStuffEndOfFrame();
-	}
-}
-
-void
-LoadingIslandScreen(const char *levelName)
-{
-	CSprite2d *splash;
-	wchar *name;
-	char str[100];
-	wchar wstr[80];
-	CRGBA col;
-
-	splash = LoadSplash(nil);
-	name = TheText.Get(levelName);
-	if(!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
+	CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
+	RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
+	if(!RsCameraBeginUpdate(Scene.camera))
 		return;
 
-	CSprite2d::SetRecipNearClip();
-	CSprite2d::InitPerFrame();
-	CFont::InitPerFrame();
-	DefinedState();
-	col = CRGBA(255, 255, 255, 255);
-	splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), col, col, col, col);
-	CFont::SetBackgroundOff();
-	CFont::SetScale(1.5f, 1.5f);
-	CFont::SetPropOn();
-	CFont::SetRightJustifyOn();
-	CFont::SetRightJustifyWrap(150.0f);
-	CFont::SetFontStyle(FONT_HEADING);
-	sprintf(str, "WELCOME TO");
-	AsciiToUnicode(str, wstr);
-	CFont::SetDropColor(CRGBA(0, 0, 0, 255));
-	CFont::SetDropShadowPosition(3);
-	CFont::SetColor(CRGBA(243, 237, 71, 255));
-	CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
-	CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME"));
-	TextCopy(wstr, name);
-	TheText.UpperCase(wstr);
-	CFont::SetColor(CRGBA(243, 237, 71, 255));
-	CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f));
-	CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr);
-	CFont::DrawFonts();
+	DefinedState(); // seems redundant, but breaks resolution change.
+	RenderMenus();
+	DoFade();
+	Render2dStuffAfterFade();
+//	CFont::DrawFonts(); // redundant
 	DoRWStuffEndOfFrame();
 }
 
-char*
-GetLevelSplashScreen(int level)
+void
+InitialiseGame(void)
 {
-	static char *splashScreens[4] = {
-		nil,
-		"splash1",
-		"splash2",
-		"splash3",
-	};
-
-	return splashScreens[level];
-}
-
-char*
-GetRandomSplashScreen(void)
-{
-	int index;
-	static int index2 = 0;
-	static char splashName[128];
-	static int splashIndex[24] = {
-		25, 22, 4, 13,
-		1, 21, 14, 16,
-		10, 12, 5, 9,
-		11, 18, 3, 2,
-		19, 23, 7, 17,
-		15, 6, 8, 20
-	};
-
-	index = splashIndex[4*index2 + CGeneral::GetRandomNumberInRange(0, 3)];
-	index2++;
-	if(index2 == 6)
-		index2 = 0;
-	sprintf(splashName, "loadsc%d", index);
-	return splashName;
-}
-
-#include "rwcore.h"
-#include "rpworld.h"
-#include "rpmatfx.h"
-#include "rpskin.h"
-#include "rphanim.h"
-#include "rtbmp.h"
-
-_TODO("temp, move this includes out of here")
-
-static RwBool 
-PluginAttach(void)
-{
-	if( !RpWorldPluginAttach() )
-	{
-		printf("Couldn't attach world plugin\n");
-		
-		return FALSE;
-	}
-	
-	if( !RpSkinPluginAttach() )
-	{
-		printf("Couldn't attach RpSkin plugin\n");
-		
-		return FALSE;
-	}
-	
-	if( !RpHAnimPluginAttach() )
-	{
-		printf("Couldn't attach RpHAnim plugin\n");
-		
-		return FALSE;
-	}
-	
-	if( !NodeNamePluginAttach() )
-	{
-		printf("Couldn't attach node name plugin\n");
-		
-		return FALSE;
-	}
-	
-	if( !CVisibilityPlugins::PluginAttach() )
-	{
-		printf("Couldn't attach visibility plugins\n");
-		
-		return FALSE;
-	}
-	
-	if( !RpAnimBlendPluginAttach() )
-	{
-		printf("Couldn't attach RpAnimBlend plugin\n");
-		
-		return FALSE;
-	}
-	
-	if( !RpMatFXPluginAttach() )
-	{
-		printf("Couldn't attach RpMatFX plugin\n");
-		
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static RwBool 
-Initialise3D(void *param)
-{
-	if (RsRwInitialise(param))
-	{
-		//
-		DebugMenuInit();
-		DebugMenuPopulate();
-		//
-
-		return CGame::InitialiseRenderWare();
-	}
-
-	return (FALSE);
-}
-
-
-static void 
-Terminate3D(void)
-{
-	CGame::ShutdownRenderWare();
-	
-	RsRwTerminate();
-
-	return;
+	LoadingScreen(nil, nil, "loadsc0");
+	CGame::Initialise("DATA\\GTA3.DAT");
 }
 
 RsEventStatus
@@ -1056,7 +1150,7 @@ AppEventHandler(RsEvent event, void *param)
 		{
 											
 			CameraSize(Scene.camera, (RwRect *)param,
-				DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
+				SCREEN_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
 			
 			return rsEVENTPROCESSED;
 		}
@@ -1133,58 +1227,615 @@ AppEventHandler(RsEvent event, void *param)
 	}
 }
 
-void PrintGameVersion()
+#ifndef MASTER
+void
+TheModelViewer(void)
 {
-	CFont::SetPropOn();
-	CFont::SetBackgroundOff();
-	CFont::SetScale(SCREEN_SCALE_X(0.7f), SCREEN_SCALE_Y(0.5f));
-	CFont::SetCentreOff();
-	CFont::SetRightJustifyOff();
-	CFont::SetBackGroundOnlyTextOff();
-	CFont::SetFontStyle(FONT_BANK);
-	CFont::SetWrapx(SCREEN_WIDTH);
-	CFont::SetDropShadowPosition(0);
-	CFont::SetDropColor(CRGBA(0, 0, 0, 255));
-	CFont::SetColor(CRGBA(235, 170, 50, 255));
+#if (defined(GTA_PS2) || defined(GTA_XBOX))
+	//TODO
+#else
+#ifdef ASPECT_RATIO_SCALE
+	CDraw::SetAspectRatio(CDraw::FindAspectRatio());
+#endif
+	CAnimViewer::Update();
+	CTimer::Update();
+	SetLightsWithTimeOfDayColour(Scene.world);
+	CRenderer::ConstructRenderList();
+	DoRWStuffStartOfFrame(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(),
+		CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(),
+		255);
 
-	strcpy(gString, "RE3");
-	AsciiToUnicode(gString, gUString);
-	CFont::PrintString(SCREEN_SCALE_X(10.5f), SCREEN_SCALE_Y(8.0f), gUString);
+	CSprite2d::InitPerFrame();
+	CFont::InitPerFrame();
+	DefinedState();
+	CVisibilityPlugins::InitAlphaEntityList();
+	CAnimViewer::Render();
+	Render2dStuff();
+	DoRWStuffEndOfFrame();
+#endif
+}
+#endif
+
+void TheGame(void)
+{
+	printf("Into TheGame!!!\n");
+
+#ifdef GTA_PS2
+	gMainHeap.PushMemId(_TODOCONST(1));
+#endif
+
+	CTimer::Initialise();
+
+#ifdef GTA_PS2
+	CGame::Initialise();
+#else
+	CGame::Initialise("DATA\\GTA3.DAT");
+#endif
+
+	char *splash = GetRandomSplashScreen(); // inlined here
+
+	LoadingScreen("Starting Game", NULL, splash);
+
+#ifdef GTA_PS2
+	if (   TheMemoryCard.CheckCardInserted(_TODOCONST(0)) == _TODOCONST(26)
+		&& TheMemoryCard.ChangeDirectory(_TODOCONST(0), TheMemoryCard.field154)
+		&& TheMemoryCard.FindMostRecentFileName(_TODOCONST(0), TheMemoryCard.field37) == 1
+		&& TheMemoryCard.CheckDataNotCorrupt(TheMemoryCard.field37))
+	{
+		strcpy(TheMemoryCard.LoadFileName, TheMemoryCard.field37);
+		TheMemoryCard.b_FoundRecentSavedGameWantToLoad = true;
+
+		if (CMenuManager::m_PrefsLanguage != TheMemoryCard.GetLanguageToLoad())
+		{
+			CMenuManager::m_PrefsLanguage = TheMemoryCard.GetLanguageToLoad();
+			TheText.Unload();
+			TheText.Load();
+		}
+
+		CGame::currLevel = TheMemoryCard.GetLevelToLoad();
+	}
+#else
+	//TODO
+#endif
+
+	while (true)
+	{
+#ifdef PS2
+		if (TheMemoryCard.m_bWantToLoad)
+#else
+		if (FrontEndMenuManager.m_bWantToLoad)
+#endif
+		{
+			char *splash1 = GetLevelSplashScreen(CGame::currLevel);
+			LoadSplash(splash1);
+		}
+
+#ifdef PS2
+		TheMemoryCard.m_bWantToLoad = false;
+#else
+		FrontEndMenuManager.m_bWantToLoad = false;
+#endif
+
+		CTimer::Update();
+
+#ifdef PS2
+		while (!(FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad))
+#else
+		while (!(FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad))
+#endif
+		{
+			CSprite2d::InitPerFrame();
+			CFont::InitPerFrame();
+
+#ifdef GTA_PS2
+			gMainHeap.PushMemId(_TODOCONST(12));
+#endif
+			CPointLights::NumLights = 0;
+			CGame::Process();
+#ifdef GTA_PS2
+			gMainHeap.PopMemId();
+#endif
+
+			DMAudio.Service();
+
+			if (CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing())
+			{
+#ifdef PS2
+				TheMemoryCard.m_bWantToLoad = false;
+#else
+				FrontEndMenuManager.m_bWantToLoad = false;
+#endif
+				FrontEndMenuManager.m_bWantToRestart = true;
+				break;
+			}
+
+#ifdef PS2
+			if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
+#else
+			if (FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad)
+#endif
+				break;
+
+			SetLightsWithTimeOfDayColour(Scene.world);
+#ifdef GTA_PS2
+			gMainHeap.PushMemId(_TODOCONST(15));
+#endif
+
+			if (!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu == true && TheCamera.GetScreenFadeStatus() != FADE_2 )
+			{
+#ifdef GTA_PS2
+				gMainHeap.PushMemId(_TODOCONST(11));
+#endif
+				CRenderer::ConstructRenderList();
+				CRenderer::PreRender();
+#ifdef GTA_PS2
+				gMainHeap.PopMemId();
+#endif
+
+				if (CWeather::LightningFlash && !CCullZones::CamNoRain())
+					DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255);
+				else
+					DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(), CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(), 255);
+
+				DefinedState();
+				RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip());
+				RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
+
+				RenderScene();
+				RenderDebugShit();
+				RenderEffects();
+
+				if ((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) && TheCamera.m_ScreenReductionPercentage > 0.0f)
+					TheCamera.SetMotionBlurAlpha(150);
+				TheCamera.RenderMotionBlur();
+
+				Render2dStuff();
+			}
+			else
+			{
+				CameraSize(Scene.camera, NULL, SCREEN_VIEWWINDOW, SCREEN_ASPECT_RATIO);
+				CVisibilityPlugins::SetRenderWareCamera(Scene.camera);
+				RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ);
+				if (!RsCameraBeginUpdate(Scene.camera))
+					break;
+			}
+
+			RenderMenus();
+
+#ifdef PS2
+			if (TheMemoryCard.m_bWantToLoad)
+#else
+			if (FrontEndMenuManager.m_bWantToLoad)
+#endif
+			{
+#ifdef GTA_PS2
+				gMainHeap.PopMemId();
+#endif
+				break;
+			}
+
+			DoFade();
+			Render2dStuffAfterFade();
+			CCredits::Render();
+
+			DoRWStuffEndOfFrame();
+
+			while (frameCount < 2)
+				;
+
+			frameCount = 0;
+
+			CTimer::Update();
+
+#ifdef GTA_PS2
+			gMainHeap.PopMemId();
+#endif
+
+			if (g_SlowMode)
+				ProcessSlowMode();
+		}
+
+		CPad::ResetCheats();
+		CPad::StopPadsShaking();
+		DMAudio.ChangeMusicMode(MUSICMODE_DISABLE);
+		CGame::ShutDownForRestart();
+		CTimer::Stop();
+
+#ifdef PS2
+		if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
+#else
+		if (FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad)
+#endif
+		{
+#ifdef PS2
+			if (TheMemoryCard.b_FoundRecentSavedGameWantToLoad)
+#else
+			if (b_FoundRecentSavedGameWantToLoad)
+#endif
+			{
+				FrontEndMenuManager.m_bWantToRestart = true;
+#ifdef PS2
+				TheMemoryCard.m_bWantToLoad = true;
+#else
+				FrontEndMenuManager.m_bWantToLoad = true;
+#endif
+			}
+
+			CGame::InitialiseWhenRestarting();
+			DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+			FrontEndMenuManager.m_bWantToRestart = false;
+
+			continue;
+		}
+
+		break;
+	}
+
+	DMAudio.Terminate();
 }
 
-void
-ValidateVersion()
+
+void SystemInit()
 {
-	int32 file = CFileMgr::OpenFile("models\\coll\\peds.col", "rb");
-	char buff[128];
-
-	if ( file != -1 )
-	{
-		CFileMgr::Seek(file, 100, SEEK_SET);
-		
-		for ( int i = 0; i < 128; i++ )
-		{
-			CFileMgr::Read(file, &buff[i], sizeof(char));
-			buff[i] -= 23;
-			if ( buff[i] == '\0' )
-				break;
-			CFileMgr::Seek(file, 99, SEEK_CUR);
-		}
-		
-		if ( !strncmp(buff, "grandtheftauto3", 15) )
-		{
-			strncpy(version_name, &buff[15], 64);
-			CFileMgr::CloseFile(file);
-			return;
-		}
-	}
-
-	LoadingScreen("Invalid version", NULL, NULL);
+#ifdef __MWERKS__
+	mwInit();
+#endif
 	
-	while(true)
-	{
+#ifdef GTA_PS2
+	InitMemoryMgr();
+#endif
+	
+#ifdef GTA_PS2
+	CFileMgr::InitCdSystem();
+	
+	char path[256];
+	
+	sprintf(path, "cdrom0:\\%s%s;1", "SYSTEM\\", "IOPRP23.IMG");
+	
+	sceSifInitRpc(0);
+	
+	while ( !sceSifRebootIop(path) )
 		;
+	while( !sceSifSyncIop() )
+		;
+	
+	sceSifInitRpc(0);
+	
+	CFileMgr::InitCdSystem();
+	
+	sceFsReset();
+#endif
+
+	CFileMgr::Initialise();
+	
+#ifdef GTA_PS2
+	CFileMgr::InitCd();
+	
+	Char modulepath[256];
+	
+	strcpy(modulepath, "cdrom0:\\");
+	strcat(modulepath, "SYSTEM\\");
+	strcat(modulepath, "SIO2MAN.IRX");
+	LoadModule(modulepath);
+	
+	strcpy(modulepath, "cdrom0:\\");
+	strcat(modulepath, "SYSTEM\\");
+	strcat(modulepath, "PADMAN.IRX");
+	LoadModule(modulepath);
+	
+	strcpy(modulepath, "cdrom0:\\");
+	strcat(modulepath, "SYSTEM\\");
+	strcat(modulepath, "LIBSD.IRX");
+	LoadModule(modulepath);
+	
+	strcpy(modulepath, "cdrom0:\\");
+	strcat(modulepath, "SYSTEM\\");
+	strcat(modulepath, "SDRDRV.IRX");
+	LoadModule(modulepath);
+	
+	strcpy(modulepath, "cdrom0:\\");
+	strcat(modulepath, "SYSTEM\\");
+	strcat(modulepath, "MCMAN.IRX");
+	LoadModule(modulepath);
+	
+	strcpy(modulepath, "cdrom0:\\");
+	strcat(modulepath, "SYSTEM\\");
+	strcat(modulepath, "MCSERV.IRX");
+	LoadModule(modulepath);
+#endif
+	
+
+#ifdef GTA_PS2
+	ThreadParam param;
+	
+	param.entry = &IdleThread;
+	param.stack = idleThreadStack;
+	param.stackSize = 2048;
+	param.initPriority = 127;
+	param.gpReg = &_gp;
+	
+	int thread = CreateThread(&param);
+	StartThread(thread, NULL);
+#else
+	//
+#endif
+	
+	
+	CPad::Initialise();
+	CPad::GetPad(0)->Mode = 0;
+	
+	CGame::frenchGame = false;
+	CGame::germanGame = false;
+	CGame::nastyGame = true;
+	CMenuManager::m_PrefsAllowNastyGame = true;
+	
+#ifdef GTA_PS2
+	int32 lang = sceScfGetLanguage();
+	if ( lang  == SCE_ITALIAN_LANGUAGE )
+		CMenuManager::m_PrefsLanguage = LANGUAGE_ITALIAN;
+	else if ( lang  == SCE_SPANISH_LANGUAGE )
+		CMenuManager::m_PrefsLanguage = LANGUAGE_SPANISH;
+	else if ( lang  == SCE_GERMAN_LANGUAGE )
+	{
+		CGame::germanGame = true;
+		CGame::nastyGame = false;
+		CMenuManager::m_PrefsAllowNastyGame = false;
+		CMenuManager::m_PrefsLanguage = LANGUAGE_GERMAN;
 	}
+	else if ( lang  == SCE_FRENCH_LANGUAGE )
+	{
+		CGame::frenchGame = true;
+		CGame::nastyGame = false;
+		CMenuManager::m_PrefsAllowNastyGame = false;
+		CMenuManager::m_PrefsLanguage = LANGUAGE_FRENCH;
+	}
+	else
+		CMenuManager::m_PrefsLanguage = LANGUAGE_AMERICAN;
+	
+	FrontEndMenuManager.InitialiseMenuContentsAfterLoadingGame();
+#else
+	//
+#endif
+	
+#ifdef PS2
+	TheMemoryCard.Init();
+#endif
+}
+
+void GameInit()
+{
+	if ( !gameAlreadyInitialised )
+	{
+#ifdef GTA_PS2
+		char path[256];
+		
+		strcpy(path, "cdrom0:\\");
+		strcat(path, "SYSTEM\\");
+		strcat(path, "CDSTREAM.IRX");
+		LoadModule(path);
+		
+		strcpy(path, "cdrom0:\\");
+		strcat(path, "SYSTEM\\");
+		strcat(path, "SAMPMAN.IRX");
+		LoadModule(path);
+		
+		strcpy(path, "cdrom0:\\");
+		strcat(path, "SYSTEM\\");
+		strcat(path, "MUSICSTR.IRX");
+		LoadModule(path);
+#endif
+		CdStreamInit(MAX_CDCHANNELS);
+		
+#ifdef PS2
+		Initialise3D(); //no params
+#else
+		//TODO
+#endif
+		
+#ifdef GTA_PS2
+		char *files[] =
+		{
+			"\\ANIM\\CUTS.IMG;1",
+			"\\ANIM\\CUTS.DIR;1",
+			"\\ANIM\\PED.IFP;1",
+			"\\MODELS\\FRONTEND.TXD;1",
+			"\\MODELS\\FONTS.TXD;1",
+			"\\MODELS\\HUD.TXD;1",
+			"\\MODELS\\PARTICLE.TXD;1",
+			"\\MODELS\\MISC.TXD;1",
+			"\\MODELS\\GENERIC.TXD;1",
+			"\\MODELS\\GTA3.DIR;1",
+			"\\TEXT\\ENGLISH.GXT;1",
+			"\\TEXT\\FRENCH.GXT;1",
+			"\\TEXT\\GERMAN.GXT;1",
+			"\\TEXT\\ITALIAN.GXT;1",
+			"\\TEXT\\SPANISH.GXT;1",
+			"\\TXD\\LOADSC0.TXD;1",
+			"\\TXD\\LOADSC1.TXD;1",
+			"\\TXD\\LOADSC2.TXD;1",
+			"\\TXD\\LOADSC3.TXD;1",
+			"\\TXD\\LOADSC4.TXD;1",
+			"\\TXD\\LOADSC5.TXD;1",
+			"\\TXD\\LOADSC6.TXD;1",
+			"\\TXD\\LOADSC7.TXD;1",
+			"\\TXD\\LOADSC8.TXD;1",
+			"\\TXD\\LOADSC9.TXD;1",
+			"\\TXD\\LOADSC10.TXD;1",
+			"\\TXD\\LOADSC11.TXD;1",
+			"\\TXD\\LOADSC12.TXD;1",
+			"\\TXD\\LOADSC13.TXD;1",
+			"\\TXD\\LOADSC14.TXD;1",
+			"\\TXD\\LOADSC15.TXD;1",
+			"\\TXD\\LOADSC16.TXD;1",
+			"\\TXD\\LOADSC17.TXD;1",
+			"\\TXD\\LOADSC18.TXD;1",
+			"\\TXD\\LOADSC19.TXD;1",
+			"\\TXD\\LOADSC20.TXD;1",
+			"\\TXD\\LOADSC21.TXD;1",
+			"\\TXD\\LOADSC22.TXD;1",
+			"\\TXD\\LOADSC23.TXD;1",
+			"\\TXD\\LOADSC24.TXD;1",
+			"\\TXD\\LOADSC25.TXD;1",
+			"\\TXD\\NEWS.TXD;1",
+			"\\MODELS\\COLL\\GENERIC.COL;1",
+			"\\MODELS\\COLL\\INDUST.COL;1",
+			"\\MODELS\\COLL\\COMMER.COL;1",
+			"\\MODELS\\COLL\\SUBURB.COL;1",
+			"\\MODELS\\COLL\\WEAPONS.COL;1",
+			"\\MODELS\\COLL\\VEHICLES.COL;1",
+			"\\MODELS\\COLL\\PEDS.COL;1",
+			"\\MODELS\\GENERIC\\AIR_VLO.DFF;1",
+			"\\MODELS\\GENERIC\\WEAPONS.DFF;1",
+			"\\MODELS\\GENERIC\\WHEELS.DFF;1",
+			"\\MODELS\\GENERIC\\LOPLYGUY.DFF;1",
+			"\\MODELS\\GENERIC\\ARROW.DFF;1",
+			"\\MODELS\\GENERIC\\ZONECYLB.DFF;1",
+			"\\DATA\\MAPS\\COMNTOP.IPL;1",
+			"\\DATA\\MAPS\\COMNBTM.IPL;1",
+			"\\DATA\\MAPS\\COMSE.IPL;1",
+			"\\DATA\\MAPS\\COMSW.IPL;1",
+			"\\DATA\\MAPS\\CULL.IPL;1",
+			"\\DATA\\MAPS\\INDUSTNE.IPL;1",
+			"\\DATA\\MAPS\\INDUSTNW.IPL;1",
+			"\\DATA\\MAPS\\INDUSTSE.IPL;1",
+			"\\DATA\\MAPS\\INDUSTSW.IPL;1",
+			"\\DATA\\MAPS\\SUBURBNE.IPL;1",
+			"\\DATA\\MAPS\\SUBURBSW.IPL;1",
+			"\\DATA\\MAPS\\OVERVIEW.IPL;1",
+			"\\DATA\\MAPS\\PROPS.IPL;1",
+			"\\DATA\\MAPS\\GTA3.IDE;1",
+			"\\DATA\\PATHS\\FLIGHT.DAT;1",
+			"\\DATA\\PATHS\\FLIGHT2.DAT;1",
+			"\\DATA\\PATHS\\FLIGHT3.DAT;1",
+			"\\DATA\\PATHS\\FLIGHT4.DAT;1",
+			"\\DATA\\PATHS\\TRACKS.DAT;1",
+			"\\DATA\\PATHS\\TRACKS2.DAT;1",
+			"\\DATA\\PATHS\\CHASE0.DAT;1",
+			"\\DATA\\PATHS\\CHASE1.DAT;1",
+			"\\DATA\\PATHS\\CHASE2.DAT;1",
+			"\\DATA\\PATHS\\CHASE3.DAT;1",
+			"\\DATA\\PATHS\\CHASE4.DAT;1",
+			"\\DATA\\PATHS\\CHASE5.DAT;1",
+			"\\DATA\\PATHS\\CHASE6.DAT;1",
+			"\\DATA\\PATHS\\CHASE7.DAT;1",
+			"\\DATA\\PATHS\\CHASE10.DAT;1",
+			"\\DATA\\PATHS\\CHASE11.DAT;1",
+			"\\DATA\\PATHS\\CHASE14.DAT;1",
+			"\\DATA\\PATHS\\CHASE16.DAT;1",
+			"\\DATA\\PATHS\\CHASE18.DAT;1",
+			"\\DATA\\PATHS\\CHASE19.DAT;1"
+		};
+		
+		for ( int32 i = 0; i < ARRAY_SIZE(files); i++ )
+			SkyRegisterFileOnCd([i]);
+#endif
+		
+		CreateDebugFont();
+		
+#ifdef GTA_PS2
+		AddIntcHandler(_TODOCONST(2), VBlankCounter, 0);
+#endif
+		
+		CameraSize(Scene.camera, NULL, DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO);
+		
+		CSprite2d::SetRecipNearClip();
+		CTxdStore::Initialise();
+#ifdef GTA_PS2
+		gMainHeap.PushMemId(_TODOCONST(9));
+#endif
+		CFont::Initialise();
+		CHud::Initialise();
+#ifdef GTA_PS2
+		gMainHeap.PopMemId();
+#endif
+
+		ValidateVersion();
+		
+#ifdef GTA_PS2
+		sceCdCLOCK rtc;
+		sceCdReadClock(&rtc);
+		uint32 seed = rtc.minute + rtc.day;
+		uint32 seed2 = (seed << 4)-seed;
+		uint32 seed3 = (seed2 << 4)-seed2;
+		srand ((seed3<<4)+rtc.second);
+#else
+		//TODO: mysrand();
+#endif
+		
+		gameAlreadyInitialised = true;
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+#ifdef __MWERKS__
+	mwInit(); // metrowerks initialisation
+#endif
+
+	SystemInit();
+	
+#ifdef PS2
+	int32 state = TheMemoryCard.CheckCardStateAtGameStartUp(_TODOCONST(0));
+		
+	if ( state == _TODOCONST(2) || state == _TODOCONST(1) && state != _TODOCONST(3) && state != _TODOCONST(0) )
+	{
+		GameInit();
+		
+		TheText.Unload();
+		TheText.Load();
+		
+		CFont::Initialise();
+		
+		FrontEndMenuManager.DrawMemoryCardStartUpMenus();
+	}
+#endif
+	
+#ifdef GTA_PS2
+	{
+		if (gameAlreadyInitialised)
+			RpSkySuspend();
+
+		InitMPEGPlayer();
+
+		PlayMPEG("cdrom0:\\MOVIES\\DMAPAL.PSS;1", false);
+
+		if (CGame::frenchGame || CGame::germanGame)
+			PlayMPEG("cdrom0:\\MOVIES\\INTROPAF.PSS;1", true);
+		else
+			PlayMPEG("cdrom0:\\MOVIES\\INTROPAL.PSS;1", true);
+
+		ShutdownMPEGPlayer();
+
+		if ( gameAlreadyInitialised )
+			RpSkyResume();
+	}
+#else
+	//TODO
+#endif
+
+	GameInit();
+
+	if ( CGame::frenchGame || CGame::germanGame )
+		LoadingScreen(NULL, version_name, "loadsc24");
+	else
+		LoadingScreen(NULL, version_name, "loadsc0");
+	
+	DMAudio.Initialise();
+	
+	TheGame();
+	
+	CGame::ShutDown();
+	
+	RwEngineStop();
+	RwEngineClose();
+	RwEngineTerm();
+	
+#ifdef __MWERKS__
+	mwExit(); // metrowerks shutdown
+#endif
+	
+	return 0;
 }
 
 STARTPATCHES
diff --git a/src/core/obrstr.cpp b/src/core/obrstr.cpp
index 3663d134..d9f7e9b4 100644
--- a/src/core/obrstr.cpp
+++ b/src/core/obrstr.cpp
@@ -1,119 +1,119 @@
-#include "common.h"
-#include "Debug.h"
-#include "obrstr.h"
-
-char obrstr[128];
-char obrstr2[128];
-
-void ObrInt(int32 n1)
-{
-	IntToStr(n1, obrstr);
-	CDebug::DebugAddText(obrstr);
-}
-
-void ObrInt2(int32 n1, int32 n2)
-{
-	IntToStr(n1, obrstr);
-	strcat(obrstr, "  ");
-	IntToStr(n2, obrstr2);
-	strcat(obrstr, obrstr2);
-	CDebug::DebugAddText(obrstr);
-}
-
-void ObrInt3(int32 n1, int32 n2, int32 n3)
-{
-	IntToStr(n1, obrstr);
-	strcat(obrstr, "  ");
-	IntToStr(n2, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n3, obrstr2);
-	strcat(obrstr, obrstr2);
-	CDebug::DebugAddText(obrstr);
-}
-
-void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4)
-{
-	IntToStr(n1, obrstr);
-	strcat(obrstr, "  ");
-	IntToStr(n2, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n3, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n4, obrstr2);
-	strcat(obrstr, obrstr2);
-	CDebug::DebugAddText(obrstr);
-}
-
-void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5)
-{
-	IntToStr(n1, obrstr);
-	strcat(obrstr, "  ");
-	IntToStr(n2, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n3, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n4, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n5, obrstr2);
-	strcat(obrstr, obrstr2);
-	CDebug::DebugAddText(obrstr);
-}
-
-void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6)
-{
-	IntToStr(n1, obrstr);
-	strcat(obrstr, "  ");
-	IntToStr(n2, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n3, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n4, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n5, obrstr2);
-	strcat(obrstr, obrstr2);
-	strcat(obrstr, "  ");
-	IntToStr(n6, obrstr2);
-	strcat(obrstr, obrstr2);
-	CDebug::DebugAddText(obrstr);
-}
-
-void IntToStr(int32 inNum, char *outStr)
-{
-	bool isNeg = inNum < 0;
-
-	if (isNeg) {
-		inNum = -inNum;
-		*outStr = '-';
-	}
-
-	int16 digits = 1;
-
-	if (inNum > 9) {
-		int32 _inNum = inNum;
-		do {
-			digits++;
-			_inNum /= 10;
-		} while (_inNum > 9);
-	}
-
-	int32 strSize = digits;
-	if (isNeg)
-		strSize++;
-
-	char *pStr = &outStr[strSize];
-	int32 i = 0;
-	do {
-		*(pStr-- - 1) = (inNum % 10) + '0';
-		inNum /= 10;
-	} while (++i < strSize);
-	outStr[strSize] = '\0';
+#include "common.h"
+#include "Debug.h"
+#include "obrstr.h"
+
+char obrstr[128];
+char obrstr2[128];
+
+void ObrInt(int32 n1)
+{
+	IntToStr(n1, obrstr);
+	CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt2(int32 n1, int32 n2)
+{
+	IntToStr(n1, obrstr);
+	strcat(obrstr, "  ");
+	IntToStr(n2, obrstr2);
+	strcat(obrstr, obrstr2);
+	CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt3(int32 n1, int32 n2, int32 n3)
+{
+	IntToStr(n1, obrstr);
+	strcat(obrstr, "  ");
+	IntToStr(n2, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n3, obrstr2);
+	strcat(obrstr, obrstr2);
+	CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4)
+{
+	IntToStr(n1, obrstr);
+	strcat(obrstr, "  ");
+	IntToStr(n2, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n3, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n4, obrstr2);
+	strcat(obrstr, obrstr2);
+	CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5)
+{
+	IntToStr(n1, obrstr);
+	strcat(obrstr, "  ");
+	IntToStr(n2, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n3, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n4, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n5, obrstr2);
+	strcat(obrstr, obrstr2);
+	CDebug::DebugAddText(obrstr);
+}
+
+void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6)
+{
+	IntToStr(n1, obrstr);
+	strcat(obrstr, "  ");
+	IntToStr(n2, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n3, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n4, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n5, obrstr2);
+	strcat(obrstr, obrstr2);
+	strcat(obrstr, "  ");
+	IntToStr(n6, obrstr2);
+	strcat(obrstr, obrstr2);
+	CDebug::DebugAddText(obrstr);
+}
+
+void IntToStr(int32 inNum, char *outStr)
+{
+	bool isNeg = inNum < 0;
+
+	if (isNeg) {
+		inNum = -inNum;
+		*outStr = '-';
+	}
+
+	int16 digits = 1;
+
+	if (inNum > 9) {
+		int32 _inNum = inNum;
+		do {
+			digits++;
+			_inNum /= 10;
+		} while (_inNum > 9);
+	}
+
+	int32 strSize = digits;
+	if (isNeg)
+		strSize++;
+
+	char *pStr = &outStr[strSize];
+	int32 i = 0;
+	do {
+		*(pStr-- - 1) = (inNum % 10) + '0';
+		inNum /= 10;
+	} while (++i < strSize);
+	outStr[strSize] = '\0';
 }
\ No newline at end of file
diff --git a/src/core/obrstr.h b/src/core/obrstr.h
index 6838afb5..c1633614 100644
--- a/src/core/obrstr.h
+++ b/src/core/obrstr.h
@@ -1,9 +1,9 @@
-#pragma once
-
-void ObrInt(int32 n1);
-void ObrInt2(int32 n1, int32 n2);
-void ObrInt3(int32 n1, int32 n2, int32 n3);
-void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4);
-void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5);
-void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6);
+#pragma once
+
+void ObrInt(int32 n1);
+void ObrInt2(int32 n1, int32 n2);
+void ObrInt3(int32 n1, int32 n2, int32 n3);
+void ObrInt4(int32 n1, int32 n2, int32 n3, int32 n4);
+void ObrInt5(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5);
+void ObrInt6(int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6);
 void IntToStr(int32 inNum, char *outStr);
\ No newline at end of file
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 6d4ff252..321ff172 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -21,10 +21,15 @@
 #include "Particle.h"
 #include "Console.h"
 #include "Debug.h"
+#include "Hud.h"
 
 #include <list>
 
+#ifndef RWLIBS
 void **rwengine = *(void***)0x5A10E1;
+#else
+extern "C" int vsprintf(char* const _Buffer, char const* const _Format, va_list  _ArgList);
+#endif
 
 DebugMenuAPI gDebugMenuAPI;
 
@@ -144,19 +149,6 @@ SpawnCar(int id)
 	}
 }
 
-static void
-LetThemFollowYou(void) {
-	CPed *player = (CPed*) FindPlayerPed();
-	for (int i = 0; i < player->m_numNearPeds; i++) {
-		CPed *nearPed = player->m_nearPeds[i];
-		if (nearPed && !nearPed->IsPlayer()) {
-			nearPed->SetObjective(OBJECTIVE_FOLLOW_PED_IN_FORMATION, (void*)player);
-			nearPed->m_pedFormation = (eFormation)(1 + (rand() & 7));
-			nearPed->bScriptObjectiveCompleted = false;
-		}
-	}
-}
-
 static void
 FixCar(void)
 {
@@ -337,7 +329,9 @@ DebugMenuPopulate(void)
 		DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); });
 		DebugMenuAddCmd("Spawn", "Spawn Rhino", [](){ SpawnCar(MI_RHINO); });
 		DebugMenuAddCmd("Spawn", "Spawn Firetruck", [](){ SpawnCar(MI_FIRETRUCK); });
+		DebugMenuAddCmd("Spawn", "Spawn Predator", [](){ SpawnCar(MI_PREDATOR); });
 
+		DebugMenuAddVarBool8("Debug", "Draw hud", (int8*)&CHud::m_Wants_To_Draw_Hud, nil);
 		DebugMenuAddVar("Debug", "Engine Status", &engineStatus, nil, 1, 0, 226, nil);
 		DebugMenuAddCmd("Debug", "Set Engine Status", SetEngineStatus);
 		DebugMenuAddCmd("Debug", "Fix Car", FixCar);
@@ -350,6 +344,9 @@ DebugMenuPopulate(void)
 		DebugMenuAddCmd("Debug", "Catalina Fly Away", CHeli::MakeCatalinaHeliFlyAway);
 		DebugMenuAddVarBool8("Debug", "Script Heli On", (int8*)0x95CD43, nil);
 
+		DebugMenuAddVarBool8("Debug", "Show Ped Paths", (int8*)&gbShowPedPaths, nil);
+		DebugMenuAddVarBool8("Debug", "Show Car Paths", (int8*)&gbShowCarPaths, nil);
+		DebugMenuAddVarBool8("Debug", "Show Car Path Links", (int8*)&gbShowCarPathsLinks, nil);
 		DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil);
 		DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil);
 		DebugMenuAddVarBool8("Debug", "Show Collision Lines", (int8*)&gbShowCollisionLines, nil);
@@ -359,8 +356,6 @@ DebugMenuPopulate(void)
 		DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil);
 		DebugMenuAddVarBool8("Debug", "Don't render Vehicles", (int8*)&gbDontRenderVehicles, nil);
 		DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil);
-
-		DebugMenuAddCmd("Debug", "Make peds follow you in formation", LetThemFollowYou);
 #ifdef TOGGLEABLE_BETA_FEATURES
 		DebugMenuAddVarBool8("Debug", "Toggle banned particles", (int8*)&CParticle::bEnableBannedParticles, nil);
 		DebugMenuAddVarBool8("Debug", "Toggle popping heads on headshot", (int8*)&CPed::bPopHeadsOnHeadshot, nil);
@@ -458,7 +453,7 @@ void re3_debug(const char *format, ...)
 	vsprintf_s(re3_buff, re3_buffsize, format, va);
 	va_end(va);
 
-//	printf("%s", re3_buff);
+	printf("%s", re3_buff);
 	CDebug::DebugAddText(re3_buff);
 }
 
diff --git a/src/core/timebars.cpp b/src/core/timebars.cpp
index 30421731..93d85f8d 100644
--- a/src/core/timebars.cpp
+++ b/src/core/timebars.cpp
@@ -1,121 +1,121 @@
-#ifndef MASTER
-#include "common.h"
-#include "Font.h"
-#include "Frontend.h"
-#include "Timer.h"
-#include "Text.h"
-
-#define MAX_TIMERS (50)
-#define MAX_MS_COLLECTED (40)
-
-// enables frame time output
-#define FRAMETIME
-
-struct sTimeBar
-{
-	char name[20];
-	float startTime;
-	float endTime;
-	int32 unk;
-};
-
-struct
-{
-	sTimeBar Timers[MAX_TIMERS];
-	uint32 count;
-} TimerBar;
-float MaxTimes[MAX_TIMERS];
-float MaxFrameTime;
-
-uint32 curMS;
-uint32 msCollected[MAX_MS_COLLECTED];
-#ifdef FRAMETIME
-float FrameInitTime;
-#endif
-
-void tbInit()
-{
-	TimerBar.count = 0;
-	uint32 i = CTimer::GetFrameCounter() & 0x7F;
-	if (i == 0) {
-		do
-			MaxTimes[i++] = 0.0f;
-		while (i != MAX_TIMERS);
-#ifdef FRAMETIME
-		MaxFrameTime = 0.0f;
-#endif
-	}
-#ifdef FRAMETIME
-	FrameInitTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
-#endif
-}
-
-void tbStartTimer(int32 unk, char *name)
-{
-	strcpy(TimerBar.Timers[TimerBar.count].name, name);
-	TimerBar.Timers[TimerBar.count].unk = unk;
-	TimerBar.Timers[TimerBar.count].startTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
-	TimerBar.count++;
-}
-
-void tbEndTimer(char* name)
-{
-	uint32 n = 1500;
-	for (uint32 i = 0; i < TimerBar.count; i++) {
-		if (strcmp(name, TimerBar.Timers[i].name) == 0)
-			n = i;
-	}
-	assert(n != 1500);
-	TimerBar.Timers[n].endTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
-}
-
-float Diag_GetFPS()
-{
-	return 39000.0f / (msCollected[(curMS - 1) % MAX_MS_COLLECTED] - msCollected[curMS % MAX_MS_COLLECTED]);
-}
-
-void tbDisplay()
-{
-	char temp[200];
-	wchar wtemp[200];
-
-#ifdef FRAMETIME
-	float FrameEndTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
-#endif
-
-	msCollected[(curMS++) % MAX_MS_COLLECTED] = RsTimer();
-	CFont::SetBackgroundOff();
-	CFont::SetBackgroundColor(CRGBA(0, 0, 0, 128));
-	CFont::SetScale(0.48f, 1.12f);
-	CFont::SetCentreOff();
-	CFont::SetJustifyOff();
-	CFont::SetWrapx(640.0f);
-	CFont::SetRightJustifyOff();
-	CFont::SetPropOn();
-	CFont::SetFontStyle(FONT_BANK);
-	sprintf(temp, "FPS: %.2f", Diag_GetFPS());
-	AsciiToUnicode(temp, wtemp);
-	CFont::SetColor(CRGBA(255, 255, 255, 255));
-	if (!CMenuManager::m_PrefsMarketing || !CMenuManager::m_PrefsDisableTutorials) {
-		CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * (4.0f / DEFAULT_SCREEN_HEIGHT), wtemp);
-
-#ifndef FINAL
-		// Timers output (my own implementation)
-		for (uint32 i = 0; i < TimerBar.count; i++) {
-			MaxTimes[i] = max(MaxTimes[i], TimerBar.Timers[i].endTime - TimerBar.Timers[i].startTime);
-			sprintf(temp, "%s: %.2f", &TimerBar.Timers[i].name[0], MaxTimes[i]);
-			AsciiToUnicode(temp, wtemp);
-			CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (i + 2)) / DEFAULT_SCREEN_HEIGHT), wtemp);
-		}
-
-#ifdef FRAMETIME
-		MaxFrameTime = max(MaxFrameTime, FrameEndTime - FrameInitTime);
-		sprintf(temp, "Frame Time: %.2f", MaxFrameTime);
-		AsciiToUnicode(temp, wtemp);
-
-		CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (TimerBar.count + 4)) / DEFAULT_SCREEN_HEIGHT), wtemp);
-#endif // FRAMETIME
-#endif // !FINAL
-	}
-}
+#ifndef MASTER
+#include "common.h"
+#include "Font.h"
+#include "Frontend.h"
+#include "Timer.h"
+#include "Text.h"
+
+#define MAX_TIMERS (50)
+#define MAX_MS_COLLECTED (40)
+
+// enables frame time output
+#define FRAMETIME
+
+struct sTimeBar
+{
+	char name[20];
+	float startTime;
+	float endTime;
+	int32 unk;
+};
+
+struct
+{
+	sTimeBar Timers[MAX_TIMERS];
+	uint32 count;
+} TimerBar;
+float MaxTimes[MAX_TIMERS];
+float MaxFrameTime;
+
+uint32 curMS;
+uint32 msCollected[MAX_MS_COLLECTED];
+#ifdef FRAMETIME
+float FrameInitTime;
+#endif
+
+void tbInit()
+{
+	TimerBar.count = 0;
+	uint32 i = CTimer::GetFrameCounter() & 0x7F;
+	if (i == 0) {
+		do
+			MaxTimes[i++] = 0.0f;
+		while (i != MAX_TIMERS);
+#ifdef FRAMETIME
+		MaxFrameTime = 0.0f;
+#endif
+	}
+#ifdef FRAMETIME
+	FrameInitTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+#endif
+}
+
+void tbStartTimer(int32 unk, char *name)
+{
+	strcpy(TimerBar.Timers[TimerBar.count].name, name);
+	TimerBar.Timers[TimerBar.count].unk = unk;
+	TimerBar.Timers[TimerBar.count].startTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+	TimerBar.count++;
+}
+
+void tbEndTimer(char* name)
+{
+	uint32 n = 1500;
+	for (uint32 i = 0; i < TimerBar.count; i++) {
+		if (strcmp(name, TimerBar.Timers[i].name) == 0)
+			n = i;
+	}
+	assert(n != 1500);
+	TimerBar.Timers[n].endTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+}
+
+float Diag_GetFPS()
+{
+	return 39000.0f / (msCollected[(curMS - 1) % MAX_MS_COLLECTED] - msCollected[curMS % MAX_MS_COLLECTED]);
+}
+
+void tbDisplay()
+{
+	char temp[200];
+	wchar wtemp[200];
+
+#ifdef FRAMETIME
+	float FrameEndTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerFrame();
+#endif
+
+	msCollected[(curMS++) % MAX_MS_COLLECTED] = RsTimer();
+	CFont::SetBackgroundOff();
+	CFont::SetBackgroundColor(CRGBA(0, 0, 0, 128));
+	CFont::SetScale(0.48f, 1.12f);
+	CFont::SetCentreOff();
+	CFont::SetJustifyOff();
+	CFont::SetWrapx(640.0f);
+	CFont::SetRightJustifyOff();
+	CFont::SetPropOn();
+	CFont::SetFontStyle(FONT_BANK);
+	sprintf(temp, "FPS: %.2f", Diag_GetFPS());
+	AsciiToUnicode(temp, wtemp);
+	CFont::SetColor(CRGBA(255, 255, 255, 255));
+	if (!CMenuManager::m_PrefsMarketing || !CMenuManager::m_PrefsDisableTutorials) {
+		CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * (4.0f / DEFAULT_SCREEN_HEIGHT), wtemp);
+
+#ifndef FINAL
+		// Timers output (my own implementation)
+		for (uint32 i = 0; i < TimerBar.count; i++) {
+			MaxTimes[i] = max(MaxTimes[i], TimerBar.Timers[i].endTime - TimerBar.Timers[i].startTime);
+			sprintf(temp, "%s: %.2f", &TimerBar.Timers[i].name[0], MaxTimes[i]);
+			AsciiToUnicode(temp, wtemp);
+			CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (i + 2)) / DEFAULT_SCREEN_HEIGHT), wtemp);
+		}
+
+#ifdef FRAMETIME
+		MaxFrameTime = max(MaxFrameTime, FrameEndTime - FrameInitTime);
+		sprintf(temp, "Frame Time: %.2f", MaxFrameTime);
+		AsciiToUnicode(temp, wtemp);
+
+		CFont::PrintString(RsGlobal.maximumWidth * (4.0f / DEFAULT_SCREEN_WIDTH), RsGlobal.maximumHeight * ((8.0f * (TimerBar.count + 4)) / DEFAULT_SCREEN_HEIGHT), wtemp);
+#endif // FRAMETIME
+#endif // !FINAL
+	}
+}
 #endif // !MASTER
\ No newline at end of file
diff --git a/src/core/timebars.h b/src/core/timebars.h
index 8ffccd8e..6d3b853e 100644
--- a/src/core/timebars.h
+++ b/src/core/timebars.h
@@ -1,6 +1,6 @@
-#pragma once
-
-void tbInit();
-void tbStartTimer(int32, char*);
-void tbEndTimer(char*);
+#pragma once
+
+void tbInit();
+void tbStartTimer(int32, char*);
+void tbEndTimer(char*);
 void tbDisplay();
\ No newline at end of file
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 8bec1ac8..25e5db48 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -62,11 +62,11 @@ CEntity::CEntity(void)
 	bRemoveFromWorld = false;
 	bHasHitWall = false;
 	bImBeingRendered = false;
-	m_flagD8 = false;
+	bTouchingWater = false;
 	bIsSubway = false;
 	bDrawLast = false;
 	bNoBrightHeadLights = false;
-	m_flagD80 = false;
+	bDoNotRender = false;
 
 	bDistanceFade = false;
 	m_flagE2 = false;
@@ -275,9 +275,9 @@ CEntity::CreateRwObject(void)
 		if(IsBuilding())
 			gBuildings++;
 		if(RwObjectGetType(m_rwObject) == rpATOMIC)
-			m_matrix.AttachRW(RwFrameGetMatrix(RpAtomicGetFrame(m_rwObject)), false);
+			m_matrix.AttachRW(RwFrameGetMatrix(RpAtomicGetFrame((RpAtomic*)m_rwObject)), false);
 		else if(RwObjectGetType(m_rwObject) == rpCLUMP)
-			m_matrix.AttachRW(RwFrameGetMatrix(RpClumpGetFrame(m_rwObject)), false);
+			m_matrix.AttachRW(RwFrameGetMatrix(RpClumpGetFrame((RpClump*)m_rwObject)), false);
 		mi->AddRef();
 	}
 }
@@ -290,7 +290,7 @@ CEntity::DeleteRwObject(void)
 	m_matrix.Detach();
 	if(m_rwObject){
 		if(RwObjectGetType(m_rwObject) == rpATOMIC){
-			f = RpAtomicGetFrame(m_rwObject);
+			f = RpAtomicGetFrame((RpAtomic*)m_rwObject);
 			RpAtomicDestroy((RpAtomic*)m_rwObject);
 			RwFrameDestroy(f);
 		}else if(RwObjectGetType(m_rwObject) == rpCLUMP)
@@ -307,9 +307,9 @@ CEntity::UpdateRwFrame(void)
 {
 	if(m_rwObject){
 		if(RwObjectGetType(m_rwObject) == rpATOMIC)
-			RwFrameUpdateObjects(RpAtomicGetFrame(m_rwObject));
+			RwFrameUpdateObjects(RpAtomicGetFrame((RpAtomic*)m_rwObject));
 		else if(RwObjectGetType(m_rwObject) == rpCLUMP)
-			RwFrameUpdateObjects(RpClumpGetFrame(m_rwObject));
+			RwFrameUpdateObjects(RpClumpGetFrame((RpClump*)m_rwObject));
 	}
 }
 
@@ -394,13 +394,13 @@ CEntity::PreRender(void)
 			}else if(GetModelIndex() == MI_GRENADE){
 				CMotionBlurStreaks::RegisterStreak((uintptr)this,
 					100, 100, 100,
-					TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(),
-					TheCamera.GetPosition() + 0.07f*TheCamera.GetRight());
+					GetPosition() - 0.07f*TheCamera.GetRight(),
+					GetPosition() + 0.07f*TheCamera.GetRight());
 			}else if(GetModelIndex() == MI_MOLOTOV){
 				CMotionBlurStreaks::RegisterStreak((uintptr)this,
 					0, 100, 0,
-					TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(),
-					TheCamera.GetPosition() + 0.07f*TheCamera.GetRight());
+					GetPosition() - 0.07f*TheCamera.GetRight(),
+					GetPosition() + 0.07f*TheCamera.GetRight());
 			}
 		}else if(GetModelIndex() == MI_MISSILE){
 			CVector pos = GetPosition();
@@ -482,9 +482,9 @@ CEntity::AttachToRwObject(RwObject *obj)
 	m_rwObject = obj;
 	if(m_rwObject){
 		if(RwObjectGetType(m_rwObject) == rpATOMIC)
-			m_matrix.Attach(RwFrameGetMatrix(RpAtomicGetFrame(m_rwObject)), false);
+			m_matrix.Attach(RwFrameGetMatrix(RpAtomicGetFrame((RpAtomic*)m_rwObject)), false);
 		else if(RwObjectGetType(m_rwObject) == rpCLUMP)
-			m_matrix.Attach(RwFrameGetMatrix(RpClumpGetFrame(m_rwObject)), false);
+			m_matrix.Attach(RwFrameGetMatrix(RpClumpGetFrame((RpClump*)m_rwObject)), false);
 		CModelInfo::GetModelInfo(m_modelIndex)->AddRef();
 	}
 }
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index 99cc7f17..ca501ba4 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -73,11 +73,11 @@ public:
 	uint32 bRemoveFromWorld : 1;
 	uint32 bHasHitWall : 1;
 	uint32 bImBeingRendered : 1;
-	uint32 m_flagD8 : 1;	// used by cBuoyancy::ProcessBuoyancy
+	uint32 bTouchingWater : 1;	// used by cBuoyancy::ProcessBuoyancy
 	uint32 bIsSubway : 1;	// set when subway, but maybe different meaning?
 	uint32 bDrawLast : 1;
 	uint32 bNoBrightHeadLights : 1;
-	uint32 m_flagD80 : 1;	// CObject visibility?
+	uint32 bDoNotRender : 1;
 
 	// flagsE
 	uint32 bDistanceFade : 1;
@@ -90,6 +90,7 @@ public:
 	CReference *m_pFirstReference;
 
 	CColModel *GetColModel(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); }
+	uint32* GetAddressOfEntityProperties() { /* AWFUL */ return (uint32*)((char*)&m_rwObject + sizeof(m_rwObject)); }
 
 	CEntity(void);
 	~CEntity(void);
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index faa8a484..9fc77a8c 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -21,7 +21,7 @@ CPhysical::CPhysical(void)
 {
 	int i;
 
-	fForceMultiplier = 1.0f;
+	m_fForceMultiplier = 1.0f;
 	m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
 	m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
 	m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
diff --git a/src/entities/Physical.h b/src/entities/Physical.h
index 1b9f0e02..6fbc3ffd 100644
--- a/src/entities/Physical.h
+++ b/src/entities/Physical.h
@@ -29,7 +29,7 @@ public:
 	CVector m_vecTurnSpeedAvg;
 	float m_fMass;
 	float m_fTurnMass;	// moment of inertia
-  float fForceMultiplier;
+	float m_fForceMultiplier;
 	float m_fAirResistance;
 	float m_fElasticity;
 	float m_fBuoyancy;
diff --git a/src/entities/Solid.h b/src/entities/Solid.h
index e67c8e29..4ca800c2 100644
--- a/src/entities/Solid.h
+++ b/src/entities/Solid.h
@@ -1,12 +1,12 @@
-#pragma once
-
-#include "Entity.h"
-
-class CSolid : public CEntity
-{
-public:
-	CSolid(void) {
-		m_type = ENTITY_TYPE_BUILDING;
-		bUsesCollision = true;
-	}
+#pragma once
+
+#include "Entity.h"
+
+class CSolid : public CEntity
+{
+public:
+	CSolid(void) {
+		m_type = ENTITY_TYPE_BUILDING;
+		bUsesCollision = true;
+	}
 };
\ No newline at end of file
diff --git a/src/math/Matrix.h b/src/math/Matrix.h
index da38cb1d..35972e7f 100644
--- a/src/math/Matrix.h
+++ b/src/math/Matrix.h
@@ -243,6 +243,17 @@ public:
 		m_matrix.pos.y = 0.0f;
 		m_matrix.pos.z = 0.0f;
 	}
+	void ResetOrientation(void) {
+		m_matrix.right.x = 1.0f;
+		m_matrix.right.y = 0.0f;
+		m_matrix.right.z = 0.0f;
+		m_matrix.up.x = 0.0f;
+		m_matrix.up.y = 1.0f;
+		m_matrix.up.z = 0.0f;
+		m_matrix.at.x = 0.0f;
+		m_matrix.at.y = 0.0f;
+		m_matrix.at.z = 1.0f;
+	}
 };
 
 
diff --git a/src/math/Vector.h b/src/math/Vector.h
index 6f544ada..1274a4b2 100644
--- a/src/math/Vector.h
+++ b/src/math/Vector.h
@@ -83,7 +83,7 @@ public:
 		return x == right.x && y == right.y && z == right.z;
 	}
 
-	bool IsZero(void) { return x == 0.0f && y == 0.0f && z == 0.0f; }
+	bool IsZero(void) const { return x == 0.0f && y == 0.0f && z == 0.0f; }
 };
 
 inline CVector operator+(const CVector &left, const CVector &right)
diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h
index a9bafb64..0c4bf934 100644
--- a/src/modelinfo/BaseModelInfo.h
+++ b/src/modelinfo/BaseModelInfo.h
@@ -2,6 +2,8 @@
 
 #include "Collision.h"
 
+#define MAX_MODEL_NAME (24)
+
 enum ModeInfoType : uint8
 {
 	MITYPE_NA        = 0,
@@ -21,7 +23,7 @@ class CBaseModelInfo
 {
 protected:
 	// TODO?: make more things protected
-	char         m_name[24];
+	char         m_name[MAX_MODEL_NAME];
 	CColModel   *m_colModel;
 	C2dEffect   *m_twodEffects;
 	int16        m_objectId;
diff --git a/src/modelinfo/MloModelInfo.h b/src/modelinfo/MloModelInfo.h
index 19ae63d5..d4344706 100644
--- a/src/modelinfo/MloModelInfo.h
+++ b/src/modelinfo/MloModelInfo.h
@@ -1,14 +1,14 @@
-#pragma once
-
-#include "ClumpModelInfo.h"
-
-class CMloModelInfo : public CClumpModelInfo
-{
-public:
-	float field_34; // draw distance?
-	int firstInstance;
-	int lastInstance;
-public:
-	CMloModelInfo(void) : CClumpModelInfo(MITYPE_MLO) {}
-	void ConstructClump();
+#pragma once
+
+#include "ClumpModelInfo.h"
+
+class CMloModelInfo : public CClumpModelInfo
+{
+public:
+	float field_34; // draw distance?
+	int firstInstance;
+	int lastInstance;
+public:
+	CMloModelInfo(void) : CClumpModelInfo(MITYPE_MLO) {}
+	void ConstructClump();
 };
\ No newline at end of file
diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp
index d956abaa..b6a95992 100644
--- a/src/modelinfo/ModelInfo.cpp
+++ b/src/modelinfo/ModelInfo.cpp
@@ -234,12 +234,6 @@ CModelInfo::RemoveColModelsFromOtherLevels(eLevelName level)
 	}
 }
 
-CStore<CInstance, MLOINSTANCESIZE>&
-CModelInfo::GetMloInstanceStore()
-{
-	return CModelInfo::ms_mloInstanceStore;
-}
-
 void
 CModelInfo::ConstructMloClumps()
 {
@@ -247,6 +241,17 @@ CModelInfo::ConstructMloClumps()
 		ms_mloModelStore.store[i].ConstructClump();
 }
 
+void
+CModelInfo::ReInit2dEffects()
+{
+	ms_2dEffectStore.clear();
+
+	for (int i = 0; i < MODELINFOSIZE; i++) {
+		if (ms_modelInfoPtrs[i])
+			ms_modelInfoPtrs[i]->Init2dEffects();
+	}
+}
+
 STARTPATCHES
 	InjectHook(0x50B310, CModelInfo::Initialise, PATCH_JUMP);
 	InjectHook(0x50B5B0, CModelInfo::ShutDown, PATCH_JUMP);
diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h
index 13756ddf..e6dec1d8 100644
--- a/src/modelinfo/ModelInfo.h
+++ b/src/modelinfo/ModelInfo.h
@@ -36,7 +36,7 @@ public:
 	static CVehicleModelInfo *AddVehicleModel(int id);
 
 	static CStore<C2dEffect, TWODFXSIZE> &Get2dEffectStore(void) { return ms_2dEffectStore; }
-	static CStore<CInstance, MLOINSTANCESIZE> &GetMloInstanceStore();
+	static CStore<CInstance, MLOINSTANCESIZE> &GetMloInstanceStore(void) { return ms_mloInstanceStore; }
 
 	static CBaseModelInfo *GetModelInfo(const char *name, int *id);
 	static CBaseModelInfo *GetModelInfo(int id){
@@ -47,4 +47,5 @@ public:
 	static bool IsBikeModel(int32 id);
 	static void RemoveColModelsFromOtherLevels(eLevelName level);
 	static void ConstructMloClumps();
+	static void ReInit2dEffects();
 };
diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp
index 7b087fbd..015c6949 100644
--- a/src/modelinfo/PedModelInfo.cpp
+++ b/src/modelinfo/PedModelInfo.cpp
@@ -216,7 +216,7 @@ CPedModelInfo::AnimatePedColModel(CColModel* colmodel, RwFrame* frame)
 			RwMatrixCopy(mat, RwFrameGetMatrix(f));
 
 			for (f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) {
-				RwMatrixTransform(mat, &f->modelling, rwCOMBINEPOSTCONCAT);
+				RwMatrixTransform(mat, RwFrameGetMatrix(f), rwCOMBINEPOSTCONCAT);
 				if (RwFrameGetParent(f) == frame)
 					break;
 			}
diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp
index 42ad635b..0c45aa12 100644
--- a/src/modelinfo/VehicleModelInfo.cpp
+++ b/src/modelinfo/VehicleModelInfo.cpp
@@ -12,6 +12,7 @@
 #include "World.h"
 #include "Vehicle.h"
 #include "Automobile.h"
+#include "Boat.h"
 #include "Train.h"
 #include "Plane.h"
 #include "Heli.h"
@@ -80,9 +81,9 @@ RwObjectNameIdAssocation carIds[] = {
 };
 
 RwObjectNameIdAssocation boatIds[] = {
-	{ "boat_moving_hi",	1,	VEHICLE_FLAG_COLLAPSE },
-	{ "boat_rudder_hi",	3,	VEHICLE_FLAG_COLLAPSE },
-	{ "windscreen",		2,	VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE },
+	{ "boat_moving_hi",	BOAT_MOVING,	VEHICLE_FLAG_COLLAPSE },
+	{ "boat_rudder_hi",	BOAT_RUDDER,	VEHICLE_FLAG_COLLAPSE },
+	{ "windscreen",		BOAT_WINDSCREEN,	VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE },
 	{ "ped_frontseat",	BOAT_POS_FRONTSEAT,	VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
 	{ nil, 0, 0 }
 };
@@ -707,7 +708,7 @@ RpMaterial*
 CVehicleModelInfo::GetEditableMaterialListCB(RpMaterial *material, void *data)
 {
 	static RwRGBA white = { 255, 255, 255, 255 };
-	RwRGBA *col;
+	const RwRGBA *col;
 	editableMatCBData *cbdata;
 
 	cbdata = (editableMatCBData*)data;
@@ -758,8 +759,8 @@ CVehicleModelInfo::SetVehicleColour(uint8 c1, uint8 c2)
 		col = ms_vehicleColourTable[c1];
 		coltex = ms_colourTextureTable[c1];
 		for(matp = m_materials1; *matp; matp++){
-			if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){
-				colp = RpMaterialGetColor(*matp);
+			if(RpMaterialGetTexture(*matp) && RwTextureGetName(RpMaterialGetTexture(*matp))[0] != '@'){
+				colp = (RwRGBA*)RpMaterialGetColor(*matp);	// get rid of const
 				colp->red = col.red;
 				colp->green = col.green;
 				colp->blue = col.blue;
@@ -773,8 +774,8 @@ CVehicleModelInfo::SetVehicleColour(uint8 c1, uint8 c2)
 		col = ms_vehicleColourTable[c2];
 		coltex = ms_colourTextureTable[c2];
 		for(matp = m_materials2; *matp; matp++){
-			if(RpMaterialGetTexture(*matp) && RpMaterialGetTexture(*matp)->name[0] != '@'){
-				colp = RpMaterialGetColor(*matp);
+			if(RpMaterialGetTexture(*matp) && RwTextureGetName(RpMaterialGetTexture(*matp))[0] != '@'){
+				colp = (RwRGBA*)RpMaterialGetColor(*matp);	// get rid of const
 				colp->red = col.red;
 				colp->green = col.green;
 				colp->blue = col.blue;
@@ -861,7 +862,7 @@ CreateCarColourTexture(uint8 r, uint8 g, uint8 b)
 	RwImageDestroy(img);
 	RwFree(pixels);
 	tex = RwTextureCreate(ras);
-	tex->name[0] = '@';
+	RwTextureGetName(tex)[0] = '@';
 	return tex;
 }
 
@@ -1058,7 +1059,7 @@ CVehicleModelInfo::LoadEnvironmentMaps(void)
 	}
 	if(gpWhiteTexture == nil){
 		gpWhiteTexture = RwTextureRead("white", nil);
-		gpWhiteTexture->name[0] = '@';
+		RwTextureGetName(gpWhiteTexture)[0] = '@';
 		RwTextureSetFilterMode(gpWhiteTexture, rwFILTERLINEAR);
 	}
 	CTxdStore::PopCurrentTxd();
diff --git a/src/modelinfo/XtraCompsModelInfo.h b/src/modelinfo/XtraCompsModelInfo.h
index bb37ffe3..9832399c 100644
--- a/src/modelinfo/XtraCompsModelInfo.h
+++ b/src/modelinfo/XtraCompsModelInfo.h
@@ -1,12 +1,12 @@
-#pragma once
-
-#include "ClumpModelInfo.h"
-
-class CXtraCompsModelInfo : public CClumpModelInfo
-{
-	int field_34;
-public:
-	CXtraCompsModelInfo(void) : CClumpModelInfo(MITYPE_XTRACOMPS) { field_34 = 0; }
-	void SetClump(RpClump*) {};
-	void Shutdown(void) {};
+#pragma once
+
+#include "ClumpModelInfo.h"
+
+class CXtraCompsModelInfo : public CClumpModelInfo
+{
+	int field_34;
+public:
+	CXtraCompsModelInfo(void) : CClumpModelInfo(MITYPE_XTRACOMPS) { field_34 = 0; }
+	void SetClump(RpClump*) {};
+	void Shutdown(void) {};
 };
\ No newline at end of file
diff --git a/src/objects/CutsceneHead.cpp b/src/objects/CutsceneHead.cpp
index 8c417973..a7722b8a 100644
--- a/src/objects/CutsceneHead.cpp
+++ b/src/objects/CutsceneHead.cpp
@@ -20,7 +20,7 @@ CCutsceneHead::CCutsceneHead(CObject *obj)
 	m_pHeadNode = RpAnimBlendClumpFindFrame((RpClump*)obj->m_rwObject, "Shead")->frame;
 	atm = (RpAtomic*)GetFirstObject(m_pHeadNode);
 	if(atm){
-		assert(RwObjectGetType(atm) == rpATOMIC);
+		assert(RwObjectGetType((RwObject*)atm) == rpATOMIC);
 		RpAtomicSetFlags(atm, RpAtomicGetFlags(atm) & ~rpATOMICRENDER);
 	}
 }
diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp
index aa366aa0..867624c7 100644
--- a/src/objects/Object.cpp
+++ b/src/objects/Object.cpp
@@ -6,12 +6,11 @@
 #include "Radar.h"
 #include "Object.h"
 #include "DummyObject.h"
-
-WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); }
-WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); }
-WRAPPER void CObject::Init(void) { EAXJMP(0x4BAEC0); }
-WRAPPER void CObject::ProcessControl(void) { EAXJMP(0x4BB040); }
-WRAPPER void CObject::Teleport(CVector) { EAXJMP(0x4BBDA0); }
+#include "Particle.h"
+#include "General.h"
+#include "ObjectData.h"
+#include "World.h"
+#include "Floater.h"
 
 int16 &CObject::nNoTempObjects = *(int16*)0x95CCA2;
 int16 &CObject::nBodyCastHealth = *(int16*)0x5F7D4C;	// 1000
@@ -28,13 +27,13 @@ CObject::CObject(void)
 	m_nCollisionDamageEffect = 0;
 	m_nSpecialCollisionResponseCases = COLLRESPONSE_NONE;
 	m_bCameraToAvoidThisObject = false;
-	ObjectCreatedBy = 0;
+	ObjectCreatedBy = UNKNOWN_OBJECT;
 	m_nEndOfLifeTime = 0;
 //	m_nRefModelIndex = -1;	// duplicate
 //	bUseVehicleColours = false;	// duplicate
 	m_colour2 = 0;
 	m_colour1 = m_colour2;
-	field_172 = 0;
+	m_nBonusValue = 0;
 	bIsPickup = false;
 	m_obj_flag2 = false;
 	bOutOfStock = false;
@@ -82,10 +81,46 @@ CObject::~CObject(void)
 		nNoTempObjects--;
 }
 
+void 
+CObject::ProcessControl(void) 
+{ 
+	CVector point, impulse;
+	if (m_nCollisionDamageEffect)
+		ObjectDamage(m_fDamageImpulse);
+	CPhysical::ProcessControl();
+	if (mod_Buoyancy.ProcessBuoyancy(this, m_fBuoyancy, &point, &impulse)) {
+		bIsInWater = true;
+		bIsStatic = false;
+		ApplyMoveForce(impulse);
+		ApplyTurnForce(impulse, point);
+		float fTimeStep = Pow(0.97f, CTimer::GetTimeStep());
+		m_vecMoveSpeed *= fTimeStep;
+		m_vecTurnSpeed *= fTimeStep;
+	}
+	if ((m_modelIndex == MI_EXPLODINGBARREL || m_modelIndex == MI_PETROLPUMP) && bHasBeenDamaged && bIsVisible
+		&& (CGeneral::GetRandomNumber() & 0x1F) == 10) {
+		bExplosionProof = true;
+		bIsVisible = false;
+		bUsesCollision = false;
+		bAffectedByGravity = false;
+		m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+	}
+}
+
+void 
+CObject::Teleport(CVector vecPos)
+{ 
+	CWorld::Remove(this);
+	m_matrix.GetPosition() = vecPos;
+	m_matrix.UpdateRW();
+	UpdateRwFrame();
+	CWorld::Add(this);
+}
+
 void
 CObject::Render(void)
 {
-	if(m_flagD80)
+	if(bDoNotRender)
 		return;
 
 	if(m_nRefModelIndex != -1 && ObjectCreatedBy == TEMP_OBJECT && bUseVehicleColours){
@@ -117,6 +152,152 @@ CObject::RemoveLighting(bool reset)
 		WorldReplaceScorchedLightsWithNormal(Scene.world);
 }
 
+void 
+CObject::ObjectDamage(float amount) 
+{
+	if (!m_nCollisionDamageEffect || !bUsesCollision)
+		return;
+	static int8 nFrameGen = 0;
+	bool bBodyCastDamageEffect = false;
+	if (m_modelIndex == MI_BODYCAST){
+		if (amount > 50.0f)
+			nBodyCastHealth = (int16)(nBodyCastHealth - 0.5f * amount);
+		if (nBodyCastHealth < 0)
+			nBodyCastHealth = 0;
+		if (nBodyCastHealth < 200)
+			bBodyCastDamageEffect = true;
+		amount = 0.0f;
+	}
+	if ((amount * m_fCollisionDamageMultiplier > 150.0f || bBodyCastDamageEffect) && m_nCollisionDamageEffect) {
+		const CVector& vecPos = m_matrix.GetPosition();
+		const float fDirectionZ = 0.0002f * amount;
+		switch (m_nCollisionDamageEffect)
+		{
+		case COLDAMAGE_EFFECT_CHANGE_MODEL: 
+			bRenderDamaged = true;
+			break;
+		case COLDAMAGE_EFFECT_SPLIT_MODEL:
+			break;
+		case COLDAMAGE_EFFECT_SMASH_COMPLETELY:
+			bIsVisible = false;
+			bUsesCollision = false;
+			bIsStatic = true;
+			bExplosionProof = true;
+			SetMoveSpeed(0.0f, 0.0f, 0.0f);
+			SetTurnSpeed(0.0f, 0.0f, 0.0f);
+			break;
+		case COLDAMAGE_EFFECT_CHANGE_THEN_SMASH:
+			if (!bRenderDamaged) {
+				bRenderDamaged = true;
+			}
+			else {
+				bIsVisible = false;
+				bUsesCollision = false;
+				bIsStatic = true;
+				bExplosionProof = true;
+				SetMoveSpeed(0.0f, 0.0f, 0.0f);
+				SetTurnSpeed(0.0f, 0.0f, 0.0f);
+			}
+			break;
+		case COLDAMAGE_EFFECT_SMASH_CARDBOX_COMPLETELY: {
+			bIsVisible = false;
+			bUsesCollision = false;
+			bIsStatic = true;
+			bExplosionProof = true;
+			SetMoveSpeed(0.0f, 0.0f, 0.0f);
+			SetTurnSpeed(0.0f, 0.0f, 0.0f);
+			const RwRGBA color = { 96, 48, 0, 255 };
+			for (int32 i = 0; i < 25; i++) {
+				CVector vecDir(CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(0.1f, 0.15f) + fDirectionZ);
+				++nFrameGen;
+				int32 currentFrame = nFrameGen & 3;
+				float fRandom = CGeneral::GetRandomNumberInRange(0.01f, 1.0f);
+				RwRGBA randomColor = { color.red * fRandom, color.green * fRandom , color.blue, color.alpha };
+				float fSize = CGeneral::GetRandomNumberInRange(0.02f, 0.18f);
+				int32 nRotationSpeed = CGeneral::GetRandomNumberInRange(-40, 80);
+				CParticle::AddParticle(PARTICLE_CAR_DEBRIS, vecPos, vecDir, nil, fSize, randomColor, nRotationSpeed, 0, currentFrame, 0);
+			}
+			PlayOneShotScriptObject(_SCRSOUND_CARDBOARD_BOX_SMASH, vecPos);
+			break;
+		}
+		case COLDAMAGE_EFFECT_SMASH_WOODENBOX_COMPLETELY: {
+			bIsVisible = false;
+			bUsesCollision = false;
+			bIsStatic = true;
+			bExplosionProof = true;
+			SetMoveSpeed(0.0f, 0.0f, 0.0f);
+			SetTurnSpeed(0.0f, 0.0f, 0.0f);
+			const RwRGBA color = { 128, 128, 128, 255 };
+			for (int32 i = 0; i < 45; i++) {
+				CVector vecDir(CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(0.1f, 0.15f) + fDirectionZ);
+				++nFrameGen;
+				int32 currentFrame = nFrameGen & 3;
+				float fRandom = CGeneral::GetRandomNumberInRange(0.5f, 0.5f);
+				RwRGBA randomColor = { color.red * fRandom, color.green * fRandom , color.blue * fRandom, color.alpha };
+				float fSize = CGeneral::GetRandomNumberInRange(0.02f, 0.18f);
+				int32 nRotationSpeed = CGeneral::GetRandomNumberInRange(-40, 80);
+				CParticle::AddParticle(PARTICLE_CAR_DEBRIS, vecPos, vecDir, nil, fSize, randomColor, nRotationSpeed, 0, currentFrame, 0);
+			}
+			PlayOneShotScriptObject(_SCRSOUND_WOODEN_BOX_SMASH, vecPos);
+			break;
+		}
+		case COLDAMAGE_EFFECT_SMASH_TRAFFICCONE_COMPLETELY: {
+			bIsVisible = false;
+			bUsesCollision = false;
+			bIsStatic = true;
+			bExplosionProof = true;
+			SetMoveSpeed(0.0f, 0.0f, 0.0f);
+			SetTurnSpeed(0.0f, 0.0f, 0.0f);
+			const RwRGBA color1 = { 200, 0, 0, 255 };
+			const RwRGBA color2 = { 200, 200, 200, 255 };
+			for (int32 i = 0; i < 10; i++) {
+				CVector vecDir(CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(0.1f, 0.15f) + fDirectionZ);
+				++nFrameGen;
+				int32 currentFrame = nFrameGen & 3;
+				RwRGBA color = color2;
+				if (nFrameGen & 1)
+					color = color1;
+				float fSize = CGeneral::GetRandomNumberInRange(0.02f, 0.18f);
+				int32 nRotationSpeed = CGeneral::GetRandomNumberInRange(-40, 80);
+				CParticle::AddParticle(PARTICLE_CAR_DEBRIS, vecPos, vecDir, nil, fSize, color, nRotationSpeed, 0, currentFrame, 0);
+			}
+			PlayOneShotScriptObject(_SCRSOUND_TYRE_BUMP, vecPos);
+			break;
+		}
+		case COLDAMAGE_EFFECT_SMASH_BARPOST_COMPLETELY: {
+			bIsVisible = false;
+			bUsesCollision = false;
+			bIsStatic = true;
+			bExplosionProof = true;
+			SetMoveSpeed(0.0f, 0.0f, 0.0f);
+			SetTurnSpeed(0.0f, 0.0f, 0.0f);
+			const RwRGBA color1 = { 200, 0, 0, 255 };
+			const RwRGBA color2 = { 200, 200, 200, 255 };
+			for (int32 i = 0; i < 32; i++) {
+				CVector vecDir(CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(-0.35f, 0.7f),
+					CGeneral::GetRandomNumberInRange(0.1f, 0.15f) + fDirectionZ);
+				++nFrameGen;
+				int32 currentFrame = nFrameGen & 3;
+				RwRGBA color = color2;
+				if (nFrameGen & 1)
+					color = color1;
+				float fSize = CGeneral::GetRandomNumberInRange(0.02f, 0.18f);
+				int32 nRotationSpeed = CGeneral::GetRandomNumberInRange(-40, 80);
+				CParticle::AddParticle(PARTICLE_CAR_DEBRIS, vecPos, vecDir, nil, fSize, color, nRotationSpeed, 0, currentFrame, 0);
+			}
+			PlayOneShotScriptObject(_SCRSOUND_COL_CAR, vecPos);
+			break;
+		}
+		}
+	}
+}
 
 void
 CObject::RefModelInfo(int32 modelId)
@@ -125,6 +306,39 @@ CObject::RefModelInfo(int32 modelId)
 	CModelInfo::GetModelInfo(modelId)->AddRef();
 }
 
+void 
+CObject::Init(void) 
+{ 
+	m_type = ENTITY_TYPE_OBJECT;;
+	CObjectData::SetObjectData(m_modelIndex, *this);
+	m_nEndOfLifeTime = 0;
+	ObjectCreatedBy = GAME_OBJECT;
+	bIsStatic = true;
+	bIsPickup = false;
+	m_obj_flag2 = false;
+	bOutOfStock = false;
+	bGlassCracked = false;
+	bGlassBroken = false;
+	bHasBeenDamaged = false;
+	bUseVehicleColours = false;
+	m_nRefModelIndex = -1;
+	m_colour1 = 0;
+	m_colour2 = 0;
+	m_nBonusValue = 0;
+	m_pCollidingEntity = nil;
+	CColPoint point;
+	CEntity* outEntity = nil;
+	const CVector& vecPos = m_matrix.GetPosition();
+	if (CWorld::ProcessVerticalLine(vecPos, vecPos.z - 10.0f, point, outEntity, true, false, false, false, false, false, nil))
+		m_pCurSurface = outEntity;
+	else
+		m_pCurSurface = nil;
+	if (m_modelIndex == MI_BODYCAST)
+		nBodyCastHealth = 1000;
+	else if (m_modelIndex == MI_BUOY)
+		bTouchingWater = true;
+}
+
 bool
 CObject::CanBeDeleted(void)
 {
@@ -142,6 +356,45 @@ CObject::CanBeDeleted(void)
 	}
 }
 
+void
+CObject::DeleteAllMissionObjects()
+{
+	CObjectPool* objectPool = CPools::GetObjectPool();
+	for (int32 i = 0; i < objectPool->GetSize(); i++) {
+		CObject* pObject = objectPool->GetSlot(i);
+		if (pObject && pObject->ObjectCreatedBy == MISSION_OBJECT) {
+			CWorld::Remove(pObject);
+			delete pObject;
+		}
+	}
+}
+
+void 
+CObject::DeleteAllTempObjects() 
+{
+	CObjectPool* objectPool = CPools::GetObjectPool();
+	for (int32 i = 0; i < objectPool->GetSize(); i++) {
+		CObject* pObject = objectPool->GetSlot(i);
+		if (pObject && pObject->ObjectCreatedBy == TEMP_OBJECT) {
+			CWorld::Remove(pObject);
+			delete pObject;
+		}
+	}
+}
+
+void 
+CObject::DeleteAllTempObjectInArea(CVector point, float fRadius) 
+{
+	CObjectPool *objectPool = CPools::GetObjectPool();
+	for (int32 i = 0; i < objectPool->GetSize(); i++) {
+		CObject *pObject = objectPool->GetSlot(i);
+		if (pObject && pObject->ObjectCreatedBy == TEMP_OBJECT && fRadius * fRadius > pObject->GetPosition().MagnitudeSqr()) {
+			CWorld::Remove(pObject);
+			delete pObject;
+		}
+	}
+}
+
 #include <new>
 
 class CObject_ : public CObject
@@ -152,6 +405,9 @@ public:
 	CObject *ctor(CDummyObject *dummy) { return ::new (this) CObject(dummy); }
 	void dtor(void) { CObject::~CObject(); }
 	void Render_(void) { CObject::Render(); }
+	void ProcessControl_(void) { CObject::ProcessControl(); }
+	bool SetupLighting_(void) { return CObject::SetupLighting(); }
+	void RemoveLighting_(bool reset) { CObject::RemoveLighting(reset); }
 };
 
 STARTPATCHES
@@ -159,5 +415,16 @@ STARTPATCHES
 	InjectHook(0x4BACE0, (CObject* (CObject::*)(int32, bool)) &CObject_::ctor, PATCH_JUMP);
 	InjectHook(0x4BAD50, (CObject* (CObject::*)(CDummyObject*)) &CObject_::ctor, PATCH_JUMP);
 	InjectHook(0x4BAE00, &CObject_::dtor, PATCH_JUMP);
+	InjectHook(0x4BB040, &CObject_::ProcessControl_, PATCH_JUMP);
+	InjectHook(0x4BBDA0, &CObject::Teleport, PATCH_JUMP);
 	InjectHook(0x4BB1E0, &CObject_::Render_, PATCH_JUMP);
+	InjectHook(0x4A7C90, &CObject_::SetupLighting_, PATCH_JUMP);
+	InjectHook(0x4A7CD0, &CObject_::RemoveLighting_, PATCH_JUMP);
+	InjectHook(0x4BB240, &CObject::ObjectDamage, PATCH_JUMP);
+	InjectHook(0x4BBD80, &CObject::RefModelInfo, PATCH_JUMP);
+	InjectHook(0x4BAEC0, &CObject::Init, PATCH_JUMP);
+	InjectHook(0x4BB010, &CObject::CanBeDeleted, PATCH_JUMP);
+	InjectHook(0x4BBE60, &CObject::DeleteAllMissionObjects, PATCH_JUMP);
+	InjectHook(0x4BBDF0, &CObject::DeleteAllTempObjects, PATCH_JUMP);
+	InjectHook(0x4BBED0, &CObject::DeleteAllTempObjectInArea, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/objects/Object.h b/src/objects/Object.h
index 27346e23..6d04c78a 100644
--- a/src/objects/Object.h
+++ b/src/objects/Object.h
@@ -3,12 +3,25 @@
 #include "Physical.h"
 
 enum {
+	UNKNOWN_OBJECT = 0,
 	GAME_OBJECT = 1,
 	MISSION_OBJECT = 2,
 	TEMP_OBJECT = 3,
 	CUTSCENE_OBJECT = 4,
 };
 
+enum {
+	COLDAMAGE_EFFECT_NONE = 0,
+	COLDAMAGE_EFFECT_CHANGE_MODEL = 1,
+	COLDAMAGE_EFFECT_SPLIT_MODEL = 2,
+	COLDAMAGE_EFFECT_SMASH_COMPLETELY = 3,
+	COLDAMAGE_EFFECT_CHANGE_THEN_SMASH = 4,
+	COLDAMAGE_EFFECT_SMASH_CARDBOX_COMPLETELY = 50,
+	COLDAMAGE_EFFECT_SMASH_WOODENBOX_COMPLETELY = 60,
+	COLDAMAGE_EFFECT_SMASH_TRAFFICCONE_COMPLETELY = 70,
+	COLDAMAGE_EFFECT_SMASH_BARPOST_COMPLETELY = 80,
+};
+
 enum {
 	COLLRESPONSE_NONE,
 	COLLRESPONSE_CHANGE_MODEL,
@@ -41,21 +54,21 @@ public:
 	int8 bHasBeenDamaged : 1;
 	int8 bUseVehicleColours : 1;
 	int8 m_obj_flag80 : 1;
-  int8 field_172; // car for a bonus pickup?
-  int8 field_173;
+	int8 m_nBonusValue; 
+	int8 field_173;
 	float m_fCollisionDamageMultiplier;
 	uint8 m_nCollisionDamageEffect;
 	uint8 m_nSpecialCollisionResponseCases;
 	bool m_bCameraToAvoidThisObject;
-  int8 field_17B;
-  int8 field_17C;
-  int8 field_17D;
-  int8 field_17E;
-  int8 field_17F;
+	int8 field_17B;
+	int8 field_17C;
+	int8 field_17D;
+	int8 field_17E;
+	int8 field_17F;
 	uint32 m_nEndOfLifeTime;
 	int16 m_nRefModelIndex;
-  int8 field_186;
-  int8 field_187;
+	int8 field_186;
+	int8 field_187;
 	CEntity *m_pCurSurface;
 	CEntity *m_pCollidingEntity;
 	int8 m_colour1, m_colour2;
@@ -74,7 +87,7 @@ public:
 	~CObject(void);
 
 	void ProcessControl(void);
-	void Teleport(CVector);
+	void Teleport(CVector vecPos);
 	void Render(void);
 	bool SetupLighting(void);
 	void RemoveLighting(bool reset);
@@ -84,6 +97,8 @@ public:
 	void Init(void);
 	bool CanBeDeleted(void);
 
-	static void DeleteAllTempObjectInArea(CVector, float);
+	static void DeleteAllMissionObjects();
+	static void DeleteAllTempObjects();
+	static void DeleteAllTempObjectInArea(CVector point, float fRadius);
 };
 static_assert(sizeof(CObject) == 0x198, "CObject: error");
diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp
index 881510e8..60827411 100644
--- a/src/objects/ParticleObject.cpp
+++ b/src/objects/ParticleObject.cpp
@@ -154,7 +154,7 @@ CParticleObject::AddObject(uint16 type, CVector const &pos, CVector const &targe
 		pobj->m_nRemoveTimer = 0;
 	
 	if ( color.alpha != 0 )
-		RwRGBAAssign(&pobj->m_Color, &color);
+		pobj->m_Color = color;
 	else
 		pobj->m_Color.alpha  = 0;
 	
diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp
index 533d7c98..a9e0580e 100644
--- a/src/peds/CivilianPed.cpp
+++ b/src/peds/CivilianPed.cpp
@@ -28,10 +28,8 @@ CCivilianPed::CivilianAI(void)
 			return;
 
 		if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) {
-			if (m_pedInObjective) {
-				if (m_pedInObjective->IsPlayer())
-					return;
-			}
+			if (m_pedInObjective && m_pedInObjective->IsPlayer())
+				return;
 		}
 		if (CTimer::GetTimeInMilliseconds() <= m_lookTimer)
 			return;
@@ -75,7 +73,7 @@ CCivilianPed::CivilianAI(void)
 				} else {
 					SetMoveState(PEDMOVE_WALK);
 				}
-			} else if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops)  {
+			} else if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops != 0)  {
 				SetFindPathAndFlee(m_threatEntity, 5000);
 				if (threatDistSqr < sq(10.0f)) {
 					SetMoveState(PEDMOVE_RUN);
@@ -170,8 +168,8 @@ CCivilianPed::CivilianAI(void)
 		if (m_threatEntity && m_threatEntity->IsPed()) {
 			CPed *threatPed = (CPed*)m_threatEntity;
 			if (m_pedStats->m_fear <= 100 - threatPed->m_pedStats->m_temper && threatPed->m_nPedType != PEDTYPE_COP) {
-				if (threatPed->GetWeapon()->IsTypeMelee() || !GetWeapon()->IsTypeMelee()) {
-					if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops) {
+				if (threatPed->GetWeapon(m_currentWeapon).IsTypeMelee() || !GetWeapon()->IsTypeMelee()) {
+					if (threatPed->IsPlayer() && FindPlayerPed()->m_pWanted->m_CurrentCops != 0) {
 						if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) {
 							SetFindPathAndFlee(m_threatEntity, 10000);
 						}
diff --git a/src/control/Gangs.cpp b/src/peds/Gangs.cpp
similarity index 93%
rename from src/control/Gangs.cpp
rename to src/peds/Gangs.cpp
index ac32ad98..c67fe599 100644
--- a/src/control/Gangs.cpp
+++ b/src/peds/Gangs.cpp
@@ -1,10 +1,9 @@
 #include "common.h"
 #include "patcher.h"
 #include "ModelIndices.h"
-#include "Gangs.h"
+#include "Gangs.h"
 #include "Weapon.h"
 
-//CGangInfo(&CGangs::Gang)[NUM_GANGS] = *(CGangInfo(*)[NUM_GANGS])*(uintptr*)0x6EDF78;
 CGangInfo CGangs::Gang[NUM_GANGS];
 
 CGangInfo::CGangInfo() :
@@ -57,20 +56,19 @@ void CGangs::SaveAllGangData(uint8 *buf, uint32 *size)
 {
 INITSAVEBUF
 
-	*size = SAVE_HEADER_SIZE + sizeof(Gang);
+	*size = SAVE_HEADER_SIZE + sizeof(Gang);
 	WriteSaveHeader(buf, 'G','N','G','\0', *size - SAVE_HEADER_SIZE);
-	for (int i = 0; i < NUM_GANGS; i++)
-		WriteSaveBuf(buf, Gang[i]);
-
+	for (int i = 0; i < NUM_GANGS; i++)
+		WriteSaveBuf(buf, Gang[i]);
+
 VALIDATESAVEBUF(*size);
 }
 
 void CGangs::LoadAllGangData(uint8 *buf, uint32 size)
 {
-	Initialise();
-
-INITSAVEBUF
-	// original: SkipSaveBuf(buf, SAVE_HEADER_SIZE);
+	Initialise();
+
+INITSAVEBUF
 	CheckSaveHeader(buf, 'G','N','G','\0', size - SAVE_HEADER_SIZE);
 
 	for (int i = 0; i < NUM_GANGS; i++)
diff --git a/src/control/Gangs.h b/src/peds/Gangs.h
similarity index 100%
rename from src/control/Gangs.h
rename to src/peds/Gangs.h
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 54816b1c..cee2b323 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -676,7 +676,7 @@ RemoveAllModelCB(RwObject *object, void *data)
 {
 	RpAtomic *atomic = (RpAtomic*)object;
 	if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) {
-		RpClumpRemoveAtomic(atomic->clump, atomic);
+		RpClumpRemoveAtomic(RpAtomicGetClump(atomic), atomic);
 		RpAtomicDestroy(atomic);
 	}
 	return object;
@@ -902,7 +902,7 @@ static RwObject*
 SetPedAtomicVisibilityCB(RwObject* object, void* data)
 {
 	if (data == nil)
-		RpAtomicSetFlags(object, 0);
+		RpAtomicSetFlags((RpAtomic*)object, 0);
 	return object;
 }
 
@@ -2733,7 +2733,6 @@ CPed::SetObjective(eObjective newObj, void *entity)
 	}
 
 #ifdef VC_PED_PORTS
-	SetObjectiveTimer(0);
 	ClearPointGunAt();
 #endif
 	bObjectiveCompleted = false;
@@ -15027,7 +15026,7 @@ CPed::ProcessBuoyancy(void)
 #endif
 
 	if (mod_Buoyancy.ProcessBuoyancy(this, GRAVITY * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) {
-		m_flagD8 = true;
+		bTouchingWater = true;
 		CEntity *entity;
 		CColPoint point;
 		if (CWorld::ProcessVerticalLine(GetPosition(), GetPosition().z - 3.0f, point, entity, false, true, false, false, false, false, false)
@@ -15093,7 +15092,7 @@ CPed::ProcessBuoyancy(void)
 		} else
 			return;
 	} else
-		m_flagD8 = false;
+		bTouchingWater = false;
 
 	if (nGenerateWaterCircles && CTimer::GetTimeInMilliseconds() >= nGenerateWaterCircles) {
 		CVector pos = GetPosition();
diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp
index cc4b0dd0..8e450ee6 100644
--- a/src/peds/PedIK.cpp
+++ b/src/peds/PedIK.cpp
@@ -340,7 +340,7 @@ CPedIK::RestoreLookAt(void)
 }
 
 void
-CPedIK::ExtractYawAndPitchWorld(RwMatrixTag *mat, float *yaw, float *pitch)
+CPedIK::ExtractYawAndPitchWorld(RwMatrix *mat, float *yaw, float *pitch)
 {
 	float f = clamp(DotProduct(mat->up, CVector(0.0f, 1.0f, 0.0f)), -1.0f, 1.0f);
 	*yaw = Acos(f);
@@ -352,7 +352,7 @@ CPedIK::ExtractYawAndPitchWorld(RwMatrixTag *mat, float *yaw, float *pitch)
 }
 
 void
-CPedIK::ExtractYawAndPitchLocal(RwMatrixTag *mat, float *yaw, float *pitch)
+CPedIK::ExtractYawAndPitchLocal(RwMatrix *mat, float *yaw, float *pitch)
 {
 	float f = clamp(DotProduct(mat->at, CVector(0.0f, 0.0f, 1.0f)), -1.0f, 1.0f);
 	*yaw = Acos(f);
diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h
index df9017f3..7b82d1ac 100644
--- a/src/peds/PedIK.h
+++ b/src/peds/PedIK.h
@@ -54,8 +54,8 @@ public:
 	void GetComponentPosition(RwV3d *pos, uint32 node);
 	static RwMatrix *GetWorldMatrix(RwFrame *source, RwMatrix *destination);
 	void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll);
-	void ExtractYawAndPitchLocal(RwMatrixTag *mat, float *yaw, float *pitch);
-	void ExtractYawAndPitchWorld(RwMatrixTag *mat, float *yaw, float *pitch);
+	void ExtractYawAndPitchLocal(RwMatrix *mat, float *yaw, float *pitch);
+	void ExtractYawAndPitchWorld(RwMatrix *mat, float *yaw, float *pitch);
 	LimbMoveStatus MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, LimbMovementInfo &moveInfo);
 	bool RestoreGunPosn(void);
 	bool LookInDirection(float phi, float theta);
diff --git a/src/peds/PedType.h b/src/peds/PedType.h
index 1f3ecb59..3d927df5 100644
--- a/src/peds/PedType.h
+++ b/src/peds/PedType.h
@@ -85,6 +85,7 @@ public:
 	static uint32 GetFlag(int type) { return ms_apPedType[type]->m_flag; }
 	static uint32 GetAvoid(int type) { return ms_apPedType[type]->m_avoid; }
 	static uint32 GetThreats(int type) { return ms_apPedType[type]->m_threats; }
+	static void SetThreats(int type, uint32 threat) { ms_apPedType[type]->m_threats = threat; }
 	static void AddThreat(int type, int threat) { ms_apPedType[type]->m_threats |= threat; }
 	static void RemoveThreat(int type, int threat) { ms_apPedType[type]->m_threats &= ~threat; }
 	static bool IsThreat(int type, int threat) { return ms_apPedType[type]->m_threats & threat; }
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index 6dbf7687..ccc0a43a 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -1,1535 +1,1535 @@
-#include "common.h"
-#include "patcher.h"
-#include "PlayerPed.h"
-#include "Wanted.h"
-#include "Fire.h"
-#include "DMAudio.h"
-#include "Pad.h"
-#include "Camera.h"
-#include "WeaponEffects.h"
-#include "ModelIndices.h"
-#include "World.h"
-#include "RpAnimBlend.h"
-#include "AnimBlendAssociation.h"
-#include "General.h"
-#include "Pools.h"
-#include "Darkel.h"
-#include "CarCtrl.h"
-
-#define PAD_MOVE_TO_GAME_WORLD_MOVE 60.0f
-
-CPlayerPed::~CPlayerPed()
-{
-	delete m_pWanted;
-}
-
-CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1)
-{
-	m_fMoveSpeed = 0.0f;
-	SetModelIndex(MI_PLAYER);
-	SetInitialState();
-
-	m_pWanted = new CWanted();
-	m_pWanted->Initialise();
-	m_pArrestingCop = nil;
-	m_currentWeapon = WEAPONTYPE_UNARMED;
-	m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
-	m_nSpeedTimer = 0;
-	m_bSpeedTimerFlag = false;
-	m_pPointGunAt = nil;
-	m_nPedState = PED_IDLE;
-	m_fMaxStamina = 150.0f;
-	m_fCurrentStamina = m_fMaxStamina;
-	m_fStaminaProgress = 0.0f;
-	m_nEvadeAmount = 0;
-	field_1367 = 0;
-	m_nShotDelay = 0;
-	field_1376 = 0.0f;
-	m_bHaveTargetSelected = false;
-	m_bHasLockOnTarget = false;
-	m_bCanBeDamaged = true;
-	m_fWalkAngle = 0.0f;
-	m_fFPSMoveHeading = 0.0f;
-	m_nTargettableObjects[0] = m_nTargettableObjects[1] = m_nTargettableObjects[2] = m_nTargettableObjects[3] = -1;
-	field_1413 = 0;
-	for (int i = 0; i < 6; i++) {
-		m_vecSafePos[i] = CVector(0.0f, 0.0f, 0.0f);
-		m_pPedAtSafePos[i] = nil;
-	}
-}
-
-void CPlayerPed::ClearWeaponTarget()
-{
-	if (m_nPedType == PEDTYPE_PLAYER1) {
-		m_pPointGunAt = nil;
-		TheCamera.ClearPlayerWeaponMode();
-		CWeaponEffects::ClearCrossHair();
-	}
- 	ClearPointGunAt();
-}
-
-void
-CPlayerPed::SetWantedLevel(int32 level)
-{
-	m_pWanted->SetWantedLevel(level);
-}
-
-void
-CPlayerPed::SetWantedLevelNoDrop(int32 level)
-{
-	m_pWanted->SetWantedLevelNoDrop(level);
-}
-
-void
-CPlayerPed::MakeObjectTargettable(int32 handle)
-{
-	for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
-		if (
-#ifdef FIX_BUGS
-			m_nTargettableObjects[i] == -1 ||
-#endif
-			CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]) == nil) {
-			m_nTargettableObjects[i] = handle;
-			return;
-		}
-	}
-}
-
-// I don't know the actual purpose of parameter
-void
-CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity)
-{
-	if (m_pedStats->m_temper < 52) {
-		m_pedStats->m_temper++;
-	} else {
-		if (annoyedByPassingEntity) {
-			if (m_pedStats->m_temper < 55) {
-				m_pedStats->m_temper++;
-			} else {
-				m_pedStats->m_temper = 46;
-			}
-		}
-	}
-}
-
-void
-CPlayerPed::ClearAdrenaline(void)
-{
-	if (m_bAdrenalineActive && m_nAdrenalineTime != 0) {
-		m_nAdrenalineTime = 0;
-		CTimer::SetTimeScale(1.0f);
-	}
-}
-
-CPlayerInfo *
-CPlayerPed::GetPlayerInfoForThisPlayerPed()
-{
-	if (CWorld::Players[0].m_pPed == this)
-		return &CWorld::Players[0];
-
-	return nil;
-}
-
-void
-CPlayerPed::SetupPlayerPed(int32 index)
-{
-	CPlayerPed *player = new CPlayerPed();
-	CWorld::Players[index].m_pPed = player;
-
-	player->SetOrientation(0.0f, 0.0f, 0.0f);
-
-	CWorld::Add(player);
-	player->m_wepAccuracy = 100;
-}
-
-void
-CPlayerPed::DeactivatePlayerPed(int32 index)
-{
-	CWorld::Remove(CWorld::Players[index].m_pPed);
-}
-
-void
-CPlayerPed::ReactivatePlayerPed(int32 index)
-{
-	CWorld::Add(CWorld::Players[index].m_pPed);
-}
-
-void
-CPlayerPed::UseSprintEnergy(void)
-{
-	if (m_fCurrentStamina > -150.0f && !CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint
-		&& !m_bAdrenalineActive) {
-		m_fCurrentStamina = m_fCurrentStamina - CTimer::GetTimeStep();
-		m_fStaminaProgress = m_fStaminaProgress + CTimer::GetTimeStep();
-	}
-
-	if (m_fStaminaProgress >= 500.0f) {
-		m_fStaminaProgress = 0;
-		if (m_fMaxStamina < 1000.0f)
-			m_fMaxStamina += 10.0f;
-	}
-}
-
-void
-CPlayerPed::MakeChangesForNewWeapon(int8 weapon)
-{
-	if (m_nPedState == PED_SNIPER_MODE) {
-		RestorePreviousState();
-		TheCamera.ClearPlayerWeaponMode();
-	}
-	SetCurrentWeapon(weapon);
-
-	GetWeapon()->m_nAmmoInClip = min(GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition);
-
-	if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAim))
-		ClearWeaponTarget();
-
-	CAnimBlendAssociation *weaponAnim = RpAnimBlendClumpGetAssociation(GetClump(), CWeaponInfo::GetWeaponInfo(WEAPONTYPE_SNIPERRIFLE)->m_AnimToPlay);
-	if (weaponAnim) {
-		weaponAnim->SetRun();
-		weaponAnim->flags |= ASSOC_FADEOUTWHENDONE;
-	}
-	TheCamera.ClearPlayerWeaponMode();
-}
-
-void
-CPlayerPed::ReApplyMoveAnims(void)
-{
-	static AnimationId moveAnims[] = { ANIM_WALK, ANIM_RUN, ANIM_SPRINT, ANIM_IDLE_STANCE, ANIM_WALK_START };
-
-	for(int i = 0; i < ARRAY_SIZE(moveAnims); i++) {
-		CAnimBlendAssociation *curMoveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), moveAnims[i]);
-		if (curMoveAssoc) {
-			if (strcmp(CAnimManager::GetAnimAssociation(m_animGroup, moveAnims[i])->hierarchy->name, curMoveAssoc->hierarchy->name) != 0) {
-				CAnimBlendAssociation *newMoveAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, moveAnims[i]);
-				newMoveAssoc->blendDelta = curMoveAssoc->blendDelta;
-				newMoveAssoc->blendAmount = curMoveAssoc->blendAmount;
-				curMoveAssoc->blendDelta = -1000.0f;
-				curMoveAssoc->flags |= ASSOC_DELETEFADEDOUT;
-			}
-		}
-	}
-}
-
-void
-CPlayerPed::SetInitialState(void)
-{
-	m_bAdrenalineActive = false;
-	m_nAdrenalineTime = 0;
-	CTimer::SetTimeStep(1.0f);
-	m_pSeekTarget = nil;
-	m_vecSeekPos = { 0.0f, 0.0f, 0.0f };
-	m_fleeFromPosX = 0.0f;
-	m_fleeFromPosY = 0.0f;
-	m_fleeFrom = nil;
-	m_fleeTimer = 0;
-	m_objective = OBJECTIVE_NONE;
-	m_prevObjective = OBJECTIVE_NONE;
-	bUsesCollision = true;
-	ClearAimFlag();
-	ClearLookFlag();
-	bIsPointingGunAt = false;
-	bRenderPedInCar = true;
-	if (m_pFire)
-		m_pFire->Extinguish();
-	RpAnimBlendClumpRemoveAllAssociations(GetClump());
-	m_nPedState = PED_IDLE;
-	SetMoveState(PEDMOVE_STILL);
-	m_nLastPedState = PED_NONE;
-	m_animGroup = ASSOCGRP_PLAYER;
-	m_fMoveSpeed = 0.0f;
-	m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
-	m_nEvadeAmount = 0;
-	m_pEvadingFrom = nil;
-	bIsPedDieAnimPlaying = false;
-	SetRealMoveAnim();
-	m_bCanBeDamaged = true;
-	m_pedStats->m_temper = 50;
-	m_fWalkAngle = 0.0f;
-}
-
-void
-CPlayerPed::SetRealMoveAnim(void)
-{
-	CAnimBlendAssociation *curWalkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK);
-	CAnimBlendAssociation *curRunAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN);
-	CAnimBlendAssociation *curSprintAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT);
-	CAnimBlendAssociation *curWalkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
-	CAnimBlendAssociation *curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
-	CAnimBlendAssociation *curRunStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
-	CAnimBlendAssociation *curRunStopRAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
-	if (bResetWalkAnims) {
-		if (curWalkAssoc)
-			curWalkAssoc->SetCurrentTime(0.0f);
-		if (curRunAssoc)
-			curRunAssoc->SetCurrentTime(0.0f);
-		if (curSprintAssoc)
-			curSprintAssoc->SetCurrentTime(0.0f);
-		bResetWalkAnims = false;
-	}
-
-	if (!curIdleAssoc)
-		curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
-	if (!curIdleAssoc)
-		curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
-
-	if ((!curRunStopAssoc || !(curRunStopAssoc->IsRunning())) && (!curRunStopRAssoc || !(curRunStopRAssoc->IsRunning()))) {
-
-		if (curRunStopAssoc && curRunStopAssoc->blendDelta >= 0.0f || curRunStopRAssoc && curRunStopRAssoc->blendDelta >= 0.0f) {
-			if (curRunStopAssoc) {
-				curRunStopAssoc->flags |= ASSOC_DELETEFADEDOUT;
-				curRunStopAssoc->blendAmount = 1.0f;
-				curRunStopAssoc->blendDelta = -8.0f;
-			} else if (curRunStopRAssoc) {
-				curRunStopRAssoc->flags |= ASSOC_DELETEFADEDOUT;
-				curRunStopRAssoc->blendAmount = 1.0f;
-				curRunStopRAssoc->blendDelta = -8.0f;
-			}
-			
-			RestoreHeadingRate();
-			if (!curIdleAssoc) {
-				if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
-						nil, true, false, false, false, false, false)) {
-					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 8.0f);
-
-				} else {
-					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
-				}
-				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
-			}
-			curIdleAssoc->blendAmount = 0.0f;
-			curIdleAssoc->blendDelta = 8.0f;
-
-		} else if (m_fMoveSpeed == 0.0f && !curSprintAssoc) {
-			if (!curIdleAssoc) {
-				if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
-						nil, true, false, false, false, false, false)) {
-					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
-					
-				} else {
-					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
-				}
-
-				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
-			}
-
-			if (m_fCurrentStamina > 0.0f && curIdleAssoc->animId == ANIM_IDLE_TIRED) {
-				CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
-
-			} else if (m_nPedState != PED_FIGHT) {
-				if (m_fCurrentStamina < 0.0f && curIdleAssoc->animId != ANIM_IDLE_TIRED
-					&& !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f, nil, true, false, false, false, false, false)) {
-					CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
-
-				} else if (curIdleAssoc->animId != ANIM_IDLE_STANCE) {
-					CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
-				}
-			}
-
-			m_nMoveState = PEDMOVE_STILL;
-		} else {
-			if (curIdleAssoc) {
-				if (curWalkStartAssoc) {
-					curWalkStartAssoc->blendAmount = 1.0f;
-					curWalkStartAssoc->blendDelta = 0.0f;
-				} else {
-					curWalkStartAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK_START);
-				}
-				if (curWalkAssoc)
-					curWalkAssoc->SetCurrentTime(0.0f);
-				if (curRunAssoc)
-					curRunAssoc->SetCurrentTime(0.0f);
-
-				delete curIdleAssoc;
-				delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
-				delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
-				delete curSprintAssoc;
-
-				curSprintAssoc = nil;
-				m_nMoveState = PEDMOVE_WALK;
-			}
-			if (curRunStopAssoc) {
-				delete curRunStopAssoc;
-				RestoreHeadingRate();
-			}
-			if (curRunStopRAssoc) {
-				delete curRunStopRAssoc;
-				RestoreHeadingRate();
-			}
-			if (!curWalkAssoc) {
-				curWalkAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK);
-				curWalkAssoc->blendAmount = 0.0f;
-			}
-			if (!curRunAssoc) {
-				curRunAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_RUN);
-				curRunAssoc->blendAmount = 0.0f;
-			}
-			if (curWalkStartAssoc && !(curWalkStartAssoc->IsRunning())) {
-				delete curWalkStartAssoc;
-				curWalkStartAssoc = nil;
-				curWalkAssoc->SetRun();
-				curRunAssoc->SetRun();
-			}
-			if (m_nMoveState == PEDMOVE_SPRINT) {
-				if (m_fCurrentStamina < 0.0f && (m_fCurrentStamina <= -150.0f || !curSprintAssoc || curSprintAssoc->blendDelta < 0.0f))
-					m_nMoveState = PEDMOVE_STILL;
-
-				if (curWalkStartAssoc)
-					m_nMoveState = PEDMOVE_STILL;
-			}
-
-			if (curSprintAssoc && (m_nMoveState != PEDMOVE_SPRINT || m_fMoveSpeed < 0.4f)) {
-				if (curSprintAssoc->blendAmount == 0.0f) {
-					curSprintAssoc->blendDelta = -1000.0f;
-					curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
-
-				} else if (curSprintAssoc->blendDelta >= 0.0f || curSprintAssoc->blendAmount >= 0.8f) {
-					if (m_fMoveSpeed < 0.4f) {
-						AnimationId runStopAnim;
-						if (curSprintAssoc->currentTime / curSprintAssoc->hierarchy->totalLength < 0.5) // double
-							runStopAnim = ANIM_RUN_STOP;
-						else
-							runStopAnim = ANIM_RUN_STOP_R;
-						CAnimBlendAssociation* newRunStopAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, runStopAnim);
-						newRunStopAssoc->blendAmount = 1.0f;
-						newRunStopAssoc->SetDeleteCallback(RestoreHeadingRateCB, this);
-						m_headingRate = 0.0f;
-						curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
-						curSprintAssoc->blendDelta = -1000.0f;
-						curWalkAssoc->flags &= ~ASSOC_RUNNING;
-						curWalkAssoc->blendAmount = 0.0f;
-						curWalkAssoc->blendDelta = 0.0f;
-						curRunAssoc->flags &= ~ASSOC_RUNNING;
-						curRunAssoc->blendAmount = 0.0f;
-						curRunAssoc->blendDelta = 0.0f;
-					} else if (curSprintAssoc->blendDelta >= 0.0f) {
-
-						// Stop sprinting when tired
-						curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
-						curSprintAssoc->blendDelta = -1.0f;
-						curRunAssoc->blendDelta = 1.0f;
-					}
-				} else if (m_fMoveSpeed < 1.0f) {
-					curSprintAssoc->blendDelta = -8.0f;
-					curRunAssoc->blendDelta = 8.0f;
-				}
-			} else if (curWalkStartAssoc) {
-				curWalkAssoc->flags &= ~ASSOC_RUNNING;
-				curRunAssoc->flags &= ~ASSOC_RUNNING;
-				curWalkAssoc->blendAmount = 0.0f;
-				curRunAssoc->blendAmount = 0.0f;
-
-			} else if (m_nMoveState == PEDMOVE_SPRINT) {
-				if (curSprintAssoc) {
-					if (curSprintAssoc->blendDelta < 0.0f) {
-						curSprintAssoc->blendDelta = 2.0f;
-						curRunAssoc->blendDelta = -2.0f;
-					}
-				} else {
-					curWalkAssoc->blendAmount = 0.0f;
-					curRunAssoc->blendAmount = 1.0f;
-					curSprintAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_SPRINT, 2.0f);
-				}
-				UseSprintEnergy();
-			} else {
-				if (m_fMoveSpeed < 1.0f) {
-					curWalkAssoc->blendAmount = 1.0f;
-					curRunAssoc->blendAmount = 0.0f;
-					m_nMoveState = PEDMOVE_WALK;
-				} else if (m_fMoveSpeed < 2.0f) {
-					curWalkAssoc->blendAmount = 2.0f - m_fMoveSpeed;
-					curRunAssoc->blendAmount = m_fMoveSpeed - 1.0f;
-					m_nMoveState = PEDMOVE_RUN;
-				} else {
-					curWalkAssoc->blendAmount = 0.0f;
-					curRunAssoc->blendAmount = 1.0f;
-					m_nMoveState = PEDMOVE_RUN;
-				}
-			}
-		}
-	}
-	if (m_bAdrenalineActive) {
-		if (CTimer::GetTimeInMilliseconds() > m_nAdrenalineTime) {
-			m_bAdrenalineActive = false;
-			CTimer::SetTimeScale(1.0f);
-			if (curWalkStartAssoc)
-				curWalkStartAssoc->speed = 1.0f;
-			if (curWalkAssoc)
-				curWalkAssoc->speed = 1.0f;
-			if (curRunAssoc)
-				curRunAssoc->speed = 1.0f;
-			if (curSprintAssoc)
-				curSprintAssoc->speed = 1.0f;
-		} else {
-			CTimer::SetTimeScale(1.0f / 3);
-			if (curWalkStartAssoc)
-				curWalkStartAssoc->speed = 2.0f;
-			if (curWalkAssoc)
-				curWalkAssoc->speed = 2.0f;
-			if (curRunAssoc)
-				curRunAssoc->speed = 2.0f;
-			if (curSprintAssoc)
-				curSprintAssoc->speed = 2.0f;
-		}
-	}
-}
-
-void
-CPlayerPed::RestoreSprintEnergy(float restoreSpeed)
-{
-	if (m_fCurrentStamina < m_fMaxStamina)
-		m_fCurrentStamina += restoreSpeed * CTimer::GetTimeStep() * 0.5f;
-}
-
-bool
-CPlayerPed::DoWeaponSmoothSpray(void)
-{
-	if (m_nPedState == PED_ATTACK && !m_pPointGunAt) {
-		eWeaponType weapon = GetWeapon()->m_eWeaponType;
-		if (weapon == WEAPONTYPE_FLAMETHROWER || weapon == WEAPONTYPE_COLT45 || weapon == WEAPONTYPE_UZI || weapon == WEAPONTYPE_SHOTGUN || 
-			weapon == WEAPONTYPE_AK47 || weapon == WEAPONTYPE_M16 || weapon == WEAPONTYPE_HELICANNON)
-			return true;
-	}
-	return false;
-}
-
-void
-CPlayerPed::DoStuffToGoOnFire(void)
-{
-	if (m_nPedState == PED_SNIPER_MODE)
-		TheCamera.ClearPlayerWeaponMode();
-}
-
-bool
-CPlayerPed::DoesTargetHaveToBeBroken(CVector target, CWeapon *weaponUsed)
-{
-	CVector distVec = target - GetPosition();
-
-	if (distVec.Magnitude() > CWeaponInfo::GetWeaponInfo(weaponUsed->m_eWeaponType)->m_fRange)
-		return true;
-
-	if (weaponUsed->m_eWeaponType != WEAPONTYPE_SHOTGUN && weaponUsed->m_eWeaponType != WEAPONTYPE_AK47)
-		return false;
-
-	distVec.Normalise();
-
-	if (DotProduct(distVec,GetForward()) < 0.4f)
-		return true;
-
-	return false;
-}
-
-// Cancels landing anim while running & jumping? I think
-void
-CPlayerPed::RunningLand(CPad *padUsed)
-{
-	CAnimBlendAssociation *landAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_LAND);
-	if (landAssoc && landAssoc->currentTime == 0.0f && m_fMoveSpeed > 1.5f
-		&& padUsed && (padUsed->GetPedWalkLeftRight() != 0.0f || padUsed->GetPedWalkUpDown() != 0.0f)) {
-
-		landAssoc->blendDelta = -1000.0f;
-		landAssoc->flags |= ASSOC_DELETEFADEDOUT;
-
-		CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_JUMP_LAND)->SetFinishCallback(FinishJumpCB, this);
-
-		if (m_nPedState == PED_JUMP)
-			RestorePreviousState();
-	}
-}
-
-bool
-CPlayerPed::IsThisPedAttackingPlayer(CPed *suspect)
-{
-	if (suspect->m_pPointGunAt == this)
-		return true;
-
-	switch (suspect->m_objective) {
-		case OBJECTIVE_KILL_CHAR_ON_FOOT:
-		case OBJECTIVE_KILL_CHAR_ANY_MEANS:
-			if (suspect->m_pedInObjective == this)
-				return true;
-
-			break;
-		default:
-			break;
-	}
-	return false;
-}
-
-void
-CPlayerPed::PlayerControlSniper(CPad *padUsed)
-{
-	ProcessWeaponSwitch(padUsed);
-	TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f;
-
-	if (!padUsed->GetTarget()) {
-		RestorePreviousState();
-		TheCamera.ClearPlayerWeaponMode();
-	}
-
-	if (padUsed->WeaponJustDown()) {
-		CVector firePos(0.0f, 0.0f, 0.6f);
-		firePos = GetMatrix() * firePos;
-		GetWeapon()->Fire(this, &firePos);
-	}
-	GetWeapon()->Update(m_audioEntityId);
-}
-
-// I think R* also used goto in here.
-void
-CPlayerPed::ProcessWeaponSwitch(CPad *padUsed)
-{
-	if (CDarkel::FrenzyOnGoing())
-		goto switchDetectDone;
-
-	if (padUsed->CycleWeaponRightJustDown() && !m_pPointGunAt) {
-
-		if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
-			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON_RUNABOUT
-			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
-			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER_RUNABOUT
-			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER
-			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER_RUNABOUT) {
-
-			for (m_nSelectedWepSlot = m_currentWeapon + 1; m_nSelectedWepSlot < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; ++m_nSelectedWepSlot) {
-				if (HasWeapon(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) {
-					goto switchDetectDone;
-				}
-			}
-			m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
-		}
-	} else if (padUsed->CycleWeaponLeftJustDown() && !m_pPointGunAt) {
-		if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
-			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
-			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER) {
-
-			for (m_nSelectedWepSlot = m_currentWeapon - 1; ; --m_nSelectedWepSlot) {
-				if (m_nSelectedWepSlot < WEAPONTYPE_UNARMED)
-					m_nSelectedWepSlot = WEAPONTYPE_DETONATOR;
-
-				if (HasWeapon(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) {
-					goto switchDetectDone;
-				}
-			}
-		}
-	} else if (CWeaponInfo::GetWeaponInfo((eWeaponType)m_currentWeapon)->m_eWeaponFire != WEAPON_FIRE_MELEE) {
-		if (GetWeapon(m_currentWeapon).m_nAmmoTotal <= 0) {
-			if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
-				&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
-				&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER) {
-
-				for (m_nSelectedWepSlot = m_currentWeapon - 1; m_nSelectedWepSlot >= 0; --m_nSelectedWepSlot) {
-					if (m_nSelectedWepSlot == WEAPONTYPE_BASEBALLBAT && HasWeapon(WEAPONTYPE_BASEBALLBAT)
-						|| GetWeapon(m_nSelectedWepSlot).m_nAmmoTotal > 0 && m_nSelectedWepSlot != WEAPONTYPE_MOLOTOV && m_nSelectedWepSlot != WEAPONTYPE_GRENADE) {
-						goto switchDetectDone;
-					}
-				}
-				m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
-			}
-		}
-	}
-
-switchDetectDone:
-	if (m_nSelectedWepSlot != m_currentWeapon) {
-		if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN && m_nPedState != PED_FIGHT)
-			MakeChangesForNewWeapon(m_nSelectedWepSlot);
-	}
-}
-
-void
-CPlayerPed::PlayerControlM16(CPad *padUsed)
-{
-	ProcessWeaponSwitch(padUsed);
-	TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f;
-
-	if (!padUsed->GetTarget()) {
-		RestorePreviousState();
-		TheCamera.ClearPlayerWeaponMode();
-	}
-
-	if (padUsed->GetWeapon()) {
-		CVector firePos(0.0f, 0.0f, 0.6f);
-		firePos = GetMatrix() * firePos;
-		GetWeapon()->Fire(this, &firePos);
-	}
-	GetWeapon()->Update(m_audioEntityId);
-}
-
-void
-CPlayerPed::PlayerControlFighter(CPad *padUsed)
-{
-	float leftRight = padUsed->GetPedWalkLeftRight();
-	float upDown = padUsed->GetPedWalkUpDown();
-	float padMove = CVector2D(leftRight, upDown).Magnitude();
-
-	if (padMove > 0.0f) {
-		m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown) - TheCamera.Orientation;
-		m_takeAStepAfterAttack = padMove > 2 * PAD_MOVE_TO_GAME_WORLD_MOVE;
-		if (padUsed->GetSprint() && padMove > 1 * PAD_MOVE_TO_GAME_WORLD_MOVE)
-			bIsAttacking = false;
-	}
-
-	if (!CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy && padUsed->JumpJustDown()) {
-		if (m_nEvadeAmount != 0 && m_pEvadingFrom) {
-			SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1);
-			m_nEvadeAmount = 0;
-			m_pEvadingFrom = nil;
-		} else {
-			SetJump();
-		}
-	}
-}
-
-void
-CPlayerPed::PlayerControl1stPersonRunAround(CPad *padUsed)
-{
-	float leftRight = padUsed->GetPedWalkLeftRight();
-	float upDown = padUsed->GetPedWalkUpDown();
-	float padMove = CVector2D(leftRight, upDown).Magnitude();
-	float padMoveInGameUnit = padMove / PAD_MOVE_TO_GAME_WORLD_MOVE;
-	if (padMoveInGameUnit > 0.0f) {
-#ifdef FREE_CAM
-		if (!CCamera::bFreeCam)
-			m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation);
-		else
-			m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown) - TheCamera.Orientation;
-#else
-		m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation);
-#endif
-		m_fMoveSpeed = min(padMoveInGameUnit, 0.07f * CTimer::GetTimeStep() + m_fMoveSpeed);
-	} else {
-		m_fMoveSpeed = 0.0f;
-	}
-
-	if (m_nPedState == PED_JUMP) {
-		if (bIsInTheAir) {
-			if (bUsesCollision && !bHitSteepSlope &&
-				(!bHitSomethingLastFrame || m_vecDamageNormal.z > 0.6f)
-				&& m_fDistanceTravelled < CTimer::GetTimeStep() * 0.02 && m_vecMoveSpeed.MagnitudeSqr() < 0.01f) {
-
-				float angleSin = Sin(m_fRotationCur); // originally sin(DEGTORAD(RADTODEG(m_fRotationCur))) o_O
-				float angleCos = Cos(m_fRotationCur);
-				ApplyMoveForce(-angleSin * 3.0f, 3.0f * angleCos, 0.05f);
-			}
-		} else if (bIsLanding) {
-			m_fMoveSpeed = 0.0f;
-		}
-	}
-	if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
-		&& padUsed->GetSprint()) {
-		m_nMoveState = PEDMOVE_SPRINT;
-	}
-	if (m_nPedState != PED_FIGHT)
-		SetRealMoveAnim();
-
-	if (!bIsInTheAir && !(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
-		&& padUsed->JumpJustDown() && m_nPedState != PED_JUMP) {
-		ClearAttack();
-		ClearWeaponTarget();
-		if (m_nEvadeAmount != 0 && m_pEvadingFrom) {
-			SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1);
-			m_nEvadeAmount = 0;
-			m_pEvadingFrom = nil;
-		} else {
-			SetJump();
-		}
-	}
-}
-
-void
-CPlayerPed::KeepAreaAroundPlayerClear(void)
-{
-	BuildPedLists();
-	for (int i = 0; i < m_numNearPeds; ++i) {
-		CPed *nearPed = m_nearPeds[i];
-		if (nearPed->CharCreatedBy == RANDOM_CHAR && !nearPed->DyingOrDead()) {
-			if (nearPed->GetIsOnScreen()) {
-				if (nearPed->m_objective == OBJECTIVE_NONE) {
-					nearPed->SetFindPathAndFlee(this, 5000, true);
-				} else {
-					if (nearPed->EnteringCar())
-						nearPed->QuitEnteringCar();
-
-					nearPed->ClearObjective();
-				}
-			} else {
-				nearPed->FlagToDestroyWhenNextProcessed();
-			}
-		}
-	}
-	CVector playerPos = (InVehicle() ? m_pMyVehicle->GetPosition() : GetPosition());
-
-	CVector pos = GetPosition();
-	int16 lastVehicle;
-	CEntity *vehicles[8];
-	CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false);
-
-	for (int i = 0; i < lastVehicle; i++) {
-		CVehicle *veh = (CVehicle*)vehicles[i];
-		if (veh->VehicleCreatedBy != MISSION_VEHICLE) {
-			if (veh->m_status != STATUS_PLAYER && veh->m_status != STATUS_PLAYER_DISABLED) {
-				if ((veh->GetPosition() - playerPos).MagnitudeSqr() > 25.0f) {
-					veh->AutoPilot.m_nTempAction = TEMPACT_WAIT;
-					veh->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 5000;
-				} else {
-					if (DotProduct2D(playerPos - veh->GetPosition(), veh->GetForward()) > 0.0f)
-						veh->AutoPilot.m_nTempAction = TEMPACT_REVERSE;
-					else
-						veh->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
-
-					veh->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000;
-				}
-				CCarCtrl::PossiblyRemoveVehicle(veh);
-			}
-		}
-	}
-}
-
-void
-CPlayerPed::EvaluateNeighbouringTarget(CEntity *candidate, CEntity **targetPtr, float *lastCloseness, float distLimit, float angleOffset, bool lookToLeft)
-{
-	CVector distVec = candidate->GetPosition() - GetPosition();
-	if (distVec.Magnitude2D() <= distLimit) {
-		if (!DoesTargetHaveToBeBroken(candidate->GetPosition(), GetWeapon())) {
-#ifdef VC_PED_PORTS
-			float angleBetweenUs = CGeneral::GetATanOfXY(candidate->GetPosition().x - TheCamera.GetPosition().x,
-															candidate->GetPosition().y - TheCamera.GetPosition().y);
-#else
-			float angleBetweenUs = CGeneral::GetATanOfXY(distVec.x, distVec.y);
-#endif
-			angleBetweenUs = CGeneral::LimitAngle(angleBetweenUs - angleOffset);
-			float closeness;
-			if (lookToLeft) {
-				closeness = angleBetweenUs > 0.0f ? -Abs(angleBetweenUs) : -100000.0f;
-			} else {
-				closeness = angleBetweenUs > 0.0f ? -100000.0f : -Abs(angleBetweenUs);
-			}
-
-			if (closeness > *lastCloseness) {
-				*targetPtr = candidate;
-				*lastCloseness = closeness;
-			}
-		}
-	}
-}
-
-void
-CPlayerPed::EvaluateTarget(CEntity *candidate, CEntity **targetPtr, float *lastCloseness, float distLimit, float angleOffset, bool priority)
-{
-	CVector distVec = candidate->GetPosition() - GetPosition();
-	float dist = distVec.Magnitude2D();
-	if (dist <= distLimit) {
-		if (!DoesTargetHaveToBeBroken(candidate->GetPosition(), GetWeapon())) {
-			float angleBetweenUs = CGeneral::GetATanOfXY(distVec.x, distVec.y);
-			angleBetweenUs = CGeneral::LimitAngle(angleBetweenUs - angleOffset);
-
-			float closeness = -dist - 5.0f * Abs(angleBetweenUs);
-			if (priority) {
-				closeness += 5.0f;
-			}
-
-			if (closeness > *lastCloseness) {
-				*targetPtr = candidate;
-				*lastCloseness = closeness;
-			}
-		}
-	}
-}
-
-bool
-CPlayerPed::FindNextWeaponLockOnTarget(CEntity *previousTarget, bool lookToLeft)
-{
-	CEntity *nextTarget = nil;
-	float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
-	// nextTarget = nil;
-	float lastCloseness = -10000.0f;
-	// unused
-	// CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
-	CVector distVec = previousTarget->GetPosition() - GetPosition();
-	float referenceBeta = CGeneral::GetATanOfXY(distVec.x, distVec.y);
-
-	for (int h = CPools::GetPedPool()->GetSize() - 1; h >= 0; h--) {
-		CPed *pedToCheck = CPools::GetPedPool()->GetSlot(h);
-		if (pedToCheck) {
-			if (pedToCheck != FindPlayerPed() && pedToCheck != previousTarget) {
-				if (!pedToCheck->DyingOrDead() && !pedToCheck->bInVehicle
-					&& pedToCheck->m_leader != FindPlayerPed() && OurPedCanSeeThisOne(pedToCheck)) {
-
-					EvaluateNeighbouringTarget(pedToCheck, &nextTarget, &lastCloseness,
-						weaponRange, referenceBeta, lookToLeft);
-				}
-			}
-		}
-	}
-	for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
-		CObject *obj = CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]);
-		if (obj)
-			EvaluateNeighbouringTarget(obj, &nextTarget, &lastCloseness, weaponRange, referenceBeta, lookToLeft);
-	}
-	if (!nextTarget)
-		return false;
-
-	m_pPointGunAt = nextTarget;
-	if (nextTarget)
-		nextTarget->RegisterReference((CEntity**)&m_pPointGunAt);
-	SetPointGunAt(nextTarget);
-	return true;
-}
-
-bool
-CPlayerPed::FindWeaponLockOnTarget(void)
-{
-	CEntity *nextTarget = nil;
-	float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
-
-	if (m_pPointGunAt) {
-		CVector distVec = m_pPointGunAt->GetPosition() - GetPosition();
-		if (distVec.Magnitude2D() > weaponRange) {
-			m_pPointGunAt = nil;
-			return false;
-		} else {
-			return true;
-		}
-	}
-
-	// nextTarget = nil;
-	float lastCloseness = -10000.0f;
-	float referenceBeta = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
-	for (int h = CPools::GetPedPool()->GetSize() - 1; h >= 0; h--) {
-		CPed *pedToCheck = CPools::GetPedPool()->GetSlot(h);
-		if (pedToCheck) {
-			if (pedToCheck != FindPlayerPed()) {
-				if (!pedToCheck->DyingOrDead() && !pedToCheck->bInVehicle
-					&& pedToCheck->m_leader != FindPlayerPed() && OurPedCanSeeThisOne(pedToCheck)) {
-
-					EvaluateTarget(pedToCheck, &nextTarget, &lastCloseness,
-						weaponRange, referenceBeta, IsThisPedAttackingPlayer(pedToCheck));
-				}
-			}
-		}
-	}
-	for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
-		CObject *obj = CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]);
-		if (obj)
-			EvaluateTarget(obj, &nextTarget, &lastCloseness, weaponRange, referenceBeta, false);
-	}
-	if (!nextTarget)
-		return false;
-
-	m_pPointGunAt = nextTarget;
-	if (nextTarget)
-		nextTarget->RegisterReference((CEntity**)&m_pPointGunAt);
-	SetPointGunAt(nextTarget);
-	return true;
-}
-
-void
-CPlayerPed::ProcessAnimGroups(void)
-{
-	AssocGroupId groupToSet;
-	if ((m_fWalkAngle <= -DEGTORAD(50.0f) || m_fWalkAngle >= DEGTORAD(50.0f))
-		&& TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam()
-		&& CanStrafeOrMouseControl()) {
-
-		if (m_fWalkAngle >= -DEGTORAD(130.0f) && m_fWalkAngle <= DEGTORAD(130.0f)) {
-			if (m_fWalkAngle > 0.0f) {
-				if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
-					groupToSet = ASSOCGRP_ROCKETLEFT;
-				else
-					groupToSet = ASSOCGRP_PLAYERLEFT;
-			} else {
-				if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
-					groupToSet = ASSOCGRP_ROCKETRIGHT;
-				else
-					groupToSet = ASSOCGRP_PLAYERRIGHT;
-			}
-		} else {
-			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
-				groupToSet = ASSOCGRP_ROCKETBACK;
-			else
-				groupToSet = ASSOCGRP_PLAYERBACK;
-		}
-	} else {
-		if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) {
-			groupToSet = ASSOCGRP_PLAYERROCKET;
-		} else {
-			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) {
-				groupToSet = ASSOCGRP_PLAYERBBBAT;
-			} else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_COLT45 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UZI) {
-				if (!GetWeapon()->IsType2Handed()) {
-					groupToSet = ASSOCGRP_PLAYER;
-				} else {
-					groupToSet = ASSOCGRP_PLAYER2ARMED;
-				}
-			} else {
-				groupToSet = ASSOCGRP_PLAYER1ARMED;
-			}
-		}
-	}
-
-	if (m_animGroup != groupToSet) {
-		m_animGroup = groupToSet;
-		ReApplyMoveAnims();
-	}
-}
-
-void
-CPlayerPed::ProcessPlayerWeapon(CPad *padUsed)
-{
-	CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
-	if (m_bHasLockOnTarget && !m_pPointGunAt) {
-		TheCamera.ClearPlayerWeaponMode();
-		CWeaponEffects::ClearCrossHair();
-		ClearPointGunAt();
-	}
-	if (!m_pFire) {
-		if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER ||
-			GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || GetWeapon()->m_eWeaponType == WEAPONTYPE_M16) {
-			if (padUsed->TargetJustDown()) {
-				SetStoredState();
-				m_nPedState = PED_SNIPER_MODE;
-#ifdef FREE_CAM
-				if (CCamera::bFreeCam && TheCamera.Cams[0].Using3rdPersonMouseCam()) {
-					m_fRotationCur = CGeneral::LimitRadianAngle(-TheCamera.Orientation);
-					SetHeading(m_fRotationCur);
-				}
-#endif
-				if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
-					TheCamera.SetNewPlayerWeaponMode(CCam::MODE_ROCKETLAUNCHER, 0, 0);
-				else if (GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE)
-					TheCamera.SetNewPlayerWeaponMode(CCam::MODE_SNIPER, 0, 0);
-				else
-					TheCamera.SetNewPlayerWeaponMode(CCam::MODE_M16_1STPERSON, 0, 0);
-
-				m_fMoveSpeed = 0.0f;
-				CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 1000.0f);
-			}
-			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER || GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE
-				|| TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON)
-				return;
-		}
-	}
-
-	if (padUsed->GetWeapon() && m_nMoveState != PEDMOVE_SPRINT) {
-		if (m_nSelectedWepSlot == m_currentWeapon) {
-			if (m_pPointGunAt) {
-#ifdef FREE_CAM
-				if (CCamera::bFreeCam && weaponInfo->m_eWeaponFire == WEAPON_FIRE_MELEE && m_fMoveSpeed < 1.0f)
-					StartFightAttack(padUsed->GetWeapon());
-				else
-#endif
-					SetAttack(m_pPointGunAt);
-			} else if (m_currentWeapon != WEAPONTYPE_UNARMED) {
-				if (m_nPedState == PED_ATTACK) {
-					if (padUsed->WeaponJustDown()) {
-						m_bHaveTargetSelected = true;
-					} else if (!m_bHaveTargetSelected) {
-						field_1376 += CTimer::GetTimeStepNonClipped();
-					}
-				} else {
-					field_1376 = 0.0f;
-					m_bHaveTargetSelected = false;
-				}
-				SetAttack(nil);
-			} else if (padUsed->WeaponJustDown()) {
-				if (m_fMoveSpeed < 1.0f)
-					StartFightAttack(padUsed->GetWeapon());
-				else
-					SetAttack(nil);
-			}
-		}
-	} else {
-		m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY;
-		if (m_nPedState == PED_ATTACK) {
-			m_bHaveTargetSelected = true;
-			bIsAttacking = false;
-		}
-	}
-
-#ifdef FREE_CAM
-	// Rotate player/arm when shooting. We don't have auto-rotation anymore
-	if (CCamera::m_bUseMouse3rdPerson && CCamera::bFreeCam &&
-		m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT) {
-
-		// Weapons except throwable and melee ones
-		if (weaponInfo->m_bCanAim || weaponInfo->m_b1stPerson || weaponInfo->m_bExpands) {
-			if ((padUsed->GetTarget() && weaponInfo->m_bCanAimWithArm) || padUsed->GetWeapon()) {
-				float limitedCam = CGeneral::LimitRadianAngle(-TheCamera.Orientation);
-
-				// On this one we can rotate arm.
-				if (weaponInfo->m_bCanAimWithArm) {
-					if (!padUsed->GetWeapon()) { // making this State != ATTACK still stops it after attack. Re-start it immediately!
-						SetPointGunAt(nil);
-						bIsPointingGunAt = false; // to not stop after attack
-					}
-
-					SetLookFlag(limitedCam, true);
-					SetAimFlag(limitedCam);
-#ifdef VC_PED_PORTS
-					SetLookTimer(INT_MAX); // removing this makes head move for real, but I experinced some bugs.
-#endif
-				} else {
-					m_fRotationDest = limitedCam;
-					m_headingRate = 50.0f;
-
-					// Anim. fix for shotgun, ak47 and m16 (we must finish rot. it quickly)
-					if (weaponInfo->m_bCanAim && padUsed->WeaponJustDown()) {
-						m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
-						float limitedRotDest = m_fRotationDest;
-
-						if (m_fRotationCur - PI > m_fRotationDest) {
-							limitedRotDest += 2 * PI;
-						} else if (PI + m_fRotationCur < m_fRotationDest) {
-							limitedRotDest -= 2 * PI;
-						}
-
-						m_fRotationCur += (limitedRotDest - m_fRotationCur) / 2;
-					}
-				}
-			} else if (weaponInfo->m_bCanAimWithArm)
-				ClearPointGunAt();
-			else
-				RestoreHeadingRate();
-		}
-	}
-#endif
-
-	if (padUsed->GetTarget() && m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT) {
-		if (m_pPointGunAt) {
-			// what??
-			if (!m_pPointGunAt
-#ifdef FREE_CAM
-				|| (!CCamera::bFreeCam && CCamera::m_bUseMouse3rdPerson)
-#else
-				|| CCamera::m_bUseMouse3rdPerson
-#endif
-				|| m_pPointGunAt->IsPed() && ((CPed*)m_pPointGunAt)->bInVehicle) {
-				ClearWeaponTarget();
-				return;
-			}
-			if (CPlayerPed::DoesTargetHaveToBeBroken(m_pPointGunAt->GetPosition(), GetWeapon())) {
-				ClearWeaponTarget();
-				return;
-			}
-			if (m_pPointGunAt) {
-				if (padUsed->ShiftTargetLeftJustDown())
-					FindNextWeaponLockOnTarget(m_pPointGunAt, true);
-				if (padUsed->ShiftTargetRightJustDown())
-					FindNextWeaponLockOnTarget(m_pPointGunAt, false);
-			}
-			TheCamera.SetNewPlayerWeaponMode(CCam::MODE_SYPHON, 0, 0);
-			TheCamera.UpdateAimingCoors(m_pPointGunAt->GetPosition());
-		}
-#ifdef FREE_CAM
-		else if ((CCamera::bFreeCam && weaponInfo->m_eWeaponFire == WEAPON_FIRE_MELEE) || (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson)) {
-#else
-		else if (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson) {
-#endif
-			if (padUsed->TargetJustDown())
-				FindWeaponLockOnTarget();
-		}
-	} else if (m_pPointGunAt) {
-		ClearWeaponTarget();
-	}
-
-	if (m_pPointGunAt) {
-#ifndef VC_PED_PORTS
-		CVector markPos = m_pPointGunAt->GetPosition();
-#else
-		CVector markPos;
-		if (m_pPointGunAt->IsPed()) {
-			((CPed*)m_pPointGunAt)->m_pedIK.GetComponentPosition((RwV3d*)markPos, PED_MID);
-		} else {
-			markPos = m_pPointGunAt->GetPosition();
-		}
-#endif
-		if (bCanPointGunAtTarget) {
-			CWeaponEffects::MarkTarget(markPos, 64, 0, 0, 255, 0.8f);
-		} else {
-			CWeaponEffects::MarkTarget(markPos, 64, 32, 0, 255, 0.8f);
-		}
-	}
-	m_bHasLockOnTarget = m_pPointGunAt != nil;
-}
-
-void
-CPlayerPed::PlayerControlZelda(CPad *padUsed)
-{
-	bool doSmoothSpray = DoWeaponSmoothSpray();
-	float camOrientation = TheCamera.Orientation;
-	float leftRight = padUsed->GetPedWalkLeftRight();
-	float upDown = padUsed->GetPedWalkUpDown();
-	float padMoveInGameUnit;
-	bool smoothSprayWithoutMove = false;
-
-	if (doSmoothSpray && upDown > 0.0f) {
-		padMoveInGameUnit = 0.0f;
-		smoothSprayWithoutMove = true;
-	} else {
-		padMoveInGameUnit = CVector2D(leftRight, upDown).Magnitude() / PAD_MOVE_TO_GAME_WORLD_MOVE;
-	}
-
-	if (padMoveInGameUnit > 0.0f || smoothSprayWithoutMove) {
-		float padHeading = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown);
-		float neededTurn = CGeneral::LimitRadianAngle(padHeading - camOrientation);
-		if (doSmoothSpray) {
-			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER || GetWeapon()->m_eWeaponType == WEAPONTYPE_COLT45
-				|| GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI)
-				m_fRotationDest = m_fRotationCur - leftRight / 128.0f * (PI / 80.0f) * CTimer::GetTimeStep();
-			else
-				m_fRotationDest = m_fRotationCur - leftRight / 128.0f * (PI / 128.0f) * CTimer::GetTimeStep();
-		} else {
-			m_fRotationDest = neededTurn;
-		}
-
-		float maxAcc = 0.07f * CTimer::GetTimeStep();
-		m_fMoveSpeed = min(padMoveInGameUnit, m_fMoveSpeed + maxAcc);
-
-	} else {
-		m_fMoveSpeed = 0.0f;
-	}
-
-	if (m_nPedState == PED_JUMP) {
-		if (bIsInTheAir) {
-			if (bUsesCollision && !bHitSteepSlope &&
-				(!bHitSomethingLastFrame || m_vecDamageNormal.z > 0.6f)
-				&& m_fDistanceTravelled < CTimer::GetTimeStep() * 0.02 && m_vecMoveSpeed.MagnitudeSqr() < 0.01f) {
-
-				float angleSin = Sin(m_fRotationCur); // originally sin(DEGTORAD(RADTODEG(m_fRotationCur))) o_O
-				float angleCos = Cos(m_fRotationCur);
-				ApplyMoveForce(-angleSin * 3.0f, 3.0f * angleCos, 0.05f);
-			}
-		} else if (bIsLanding) {
-			m_fMoveSpeed = 0.0f;
-		}
-	}
-
-	if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
-		&& padUsed->GetSprint()) {
-		m_nMoveState = PEDMOVE_SPRINT;
-	}
-	if (m_nPedState != PED_FIGHT)
-		SetRealMoveAnim();
-
-	if (!bIsInTheAir && !(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
-		&& padUsed->JumpJustDown() && m_nPedState != PED_JUMP) {
-		ClearAttack();
-		ClearWeaponTarget();
-		if (m_nEvadeAmount != 0 && m_pEvadingFrom) {
-			SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1);
-			m_nEvadeAmount = 0;
-			m_pEvadingFrom = nil;
-		} else {
-			SetJump();
-		}
-	}
-}
-
-void
-CPlayerPed::ProcessControl(void)
-{
-	if (m_nEvadeAmount != 0)
-		--m_nEvadeAmount;
-
-	if (m_nEvadeAmount == 0)
-		m_pEvadingFrom = nil;
-
-	if (m_pCurrentPhysSurface && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) {
-		bTryingToReachDryLand = true;
-	} else if (!(((uint8)CTimer::GetFrameCounter() + m_randomSeed) & 0xF)) {
-		CVehicle *nearVeh = (CVehicle*)CWorld::TestSphereAgainstWorld(GetPosition(), 7.0f, nil,
-								false, true, false, false, false, false);
-		if (nearVeh && nearVeh->IsBoat())
-			bTryingToReachDryLand = true;
-		else
-			bTryingToReachDryLand = false;
-	}
-	CPed::ProcessControl();
-	if (bWasPostponed)
-		return;
-
-	CPad *padUsed = CPad::GetPad(0);
-	m_pWanted->Update();
-	CEntity::PruneReferences();
-
-	if (m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT)
-		RestoreSprintEnergy(1.0f);
-	else if (m_nMoveState == PEDMOVE_RUN)
-		RestoreSprintEnergy(0.3f);
-
-	if (m_nPedState == PED_DEAD) {
-		ClearWeaponTarget();
-		return;
-	}
-	if (m_nPedState == PED_DIE) {
-		ClearWeaponTarget();
-		if (CTimer::GetTimeInMilliseconds() > m_bloodyFootprintCountOrDeathTime + 4000)
-			SetDead();
-		return;
-	}
-	if (m_nPedState == PED_DRIVING && m_objective != OBJECTIVE_LEAVE_VEHICLE) {
-		if (m_pMyVehicle->IsCar() && ((CAutomobile*)m_pMyVehicle)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) == DOOR_STATUS_SWINGING) {
-			CAnimBlendAssociation *rollDoorAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_ROLLDOOR);
-			if (!rollDoorAssoc) {
-				rollDoorAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_ROLLDOOR_LOW);
-			}
-
-			// These comparisons are wrong, they return uint16
-			if (m_pMyVehicle->m_nGettingOutFlags & CAR_DOOR_FLAG_LF || rollDoorAssoc || padUsed
-				&& (padUsed->GetAccelerate() != 0.0f || padUsed->GetSteeringLeftRight() != 0.0f
-					|| padUsed->GetBrake() != 0.0f)) {
-
-				if (rollDoorAssoc)
-					m_pMyVehicle->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR, rollDoorAssoc->currentTime);
-			} else {
-				m_pMyVehicle->m_nGettingOutFlags |= CAR_DOOR_FLAG_LF;
-				if (m_pMyVehicle->bLowVehicle)
-					rollDoorAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ROLLDOOR_LOW);
-				else
-					rollDoorAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ROLLDOOR);
-
-				rollDoorAssoc->SetFinishCallback(PedAnimDoorCloseRollingCB, this);
-			}
-		}
-		return;
-	}
-	if (m_objective == OBJECTIVE_NONE)
-		m_nMoveState = PEDMOVE_STILL;
-	if (bIsLanding)
-		RunningLand(padUsed);
-	if (padUsed && padUsed->WeaponJustDown() && m_nPedState != PED_SNIPER_MODE) {
-
-		// ...Really?
-		eWeaponType playerWeapon = FindPlayerPed()->GetWeapon()->m_eWeaponType;
-		if (playerWeapon == WEAPONTYPE_SNIPERRIFLE) {
-			DMAudio.PlayFrontEndSound(SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM, 0);
-		} else if (playerWeapon == WEAPONTYPE_ROCKETLAUNCHER) {
-			DMAudio.PlayFrontEndSound(SOUND_WEAPON_ROCKET_SHOT_NO_ZOOM, 0);
-		}
-	}
-
-	switch (m_nPedState) {
-		case PED_NONE:
-		case PED_IDLE:
-		case PED_FLEE_POS:
-		case PED_FLEE_ENTITY:
-		case PED_ATTACK:
-		case PED_FIGHT:
-		case PED_AIM_GUN:
-			if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG400)) {
-				if (TheCamera.Cams[0].Using3rdPersonMouseCam()) {
-					if (padUsed)
-						PlayerControl1stPersonRunAround(padUsed);
-				} else if (m_nPedState == PED_FIGHT) {
-					if (padUsed)
-						PlayerControlFighter(padUsed);
-				} else if (padUsed) {
-					PlayerControlZelda(padUsed);
-				}
-			}
-			if (IsPedInControl() && padUsed)
-				ProcessPlayerWeapon(padUsed);
-			break;
-		case PED_LOOK_ENTITY:
-		case PED_LOOK_HEADING:
-		case PED_WANDER_RANGE:
-		case PED_WANDER_PATH:
-		case PED_PURSUE:
-		case PED_FOLLOW_PATH:
-		case PED_ROCKET_ODE:
-		case PED_DUMMY:
-		case PED_PAUSE:
-		case PED_FACE_PHONE:
-		case PED_MAKE_CALL:
-		case PED_CHAT:
-		case PED_MUG:
-		case PED_AI_CONTROL:
-		case PED_FOLLOW_ROUTE:
-		case PED_CPR:
-		case PED_SOLICIT:
-		case PED_BUY_ICECREAM:
-		case PED_INVESTIGATE:
-		case PED_STEP_AWAY:
-		case PED_ON_FIRE:
-		case PED_UNKNOWN:
-		case PED_STATES_NO_AI:
-		case PED_STAGGER:
-		case PED_DIVE_AWAY:
-		case PED_STATES_NO_ST:
-		case PED_ARREST_PLAYER:
-		case PED_DRIVING:
-		case PED_PASSENGER:
-		case PED_TAXI_PASSENGER:
-		case PED_OPEN_DOOR:
-		case PED_DIE:
-		case PED_DEAD:
-		case PED_HANDS_UP:
-			break;
-		case PED_SEEK_ENTITY:
-			m_vecSeekPos = m_pSeekTarget->GetPosition();
-
-			// fall through
-		case PED_SEEK_POS:
-			switch (m_nMoveState) {
-				case PEDMOVE_WALK:
-					m_fMoveSpeed = 1.0f;
-					break;
-				case PEDMOVE_RUN:
-					m_fMoveSpeed = 1.8f;
-					break;
-				case PEDMOVE_SPRINT:
-					m_fMoveSpeed = 2.5f;
-					break;
-				default:
-					m_fMoveSpeed = 0.0f;
-					break;
-			}
-			SetRealMoveAnim();
-			if (Seek()) {
-				RestorePreviousState();
-				SetMoveState(PEDMOVE_STILL);
-			}
-			break;
-		case PED_SNIPER_MODE:
-			if (FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_M16) {
-				if (padUsed)
-					PlayerControlM16(padUsed);
-			} else if (padUsed) {
-				PlayerControlSniper(padUsed);
-			}
-			break;
-		case PED_SEEK_CAR:
-		case PED_SEEK_IN_BOAT:
-			if (bVehEnterDoorIsBlocked || bKindaStayInSamePlace) {
-				m_fMoveSpeed = 0.0f;
-			} else {
-				m_fMoveSpeed = min(2.0f, 2.0f * (m_vecSeekPos - GetPosition()).Magnitude2D());
-			}
-			if (padUsed && !padUsed->ArePlayerControlsDisabled()) {
-				if (padUsed->GetTarget() || padUsed->GetLeftStickXJustDown() || padUsed->GetLeftStickYJustDown() ||
-					padUsed->GetDPadUpJustDown() || padUsed->GetDPadDownJustDown() || padUsed->GetDPadLeftJustDown() ||
-					padUsed->GetDPadRightJustDown()) {
-
-					RestorePreviousState();
-					if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) {
-						RestorePreviousObjective();
-					}
-				}
-			}
-			if (padUsed && padUsed->GetSprint())
-				m_nMoveState = PEDMOVE_SPRINT;
-			SetRealMoveAnim();
-			break;
-		case PED_JUMP:
-			if (padUsed)
-				PlayerControlZelda(padUsed);
-			if (bIsLanding)
-				break;
-
-			// This has been added later it seems
-			return;
-		case PED_FALL:
-		case PED_GETUP:
-		case PED_ENTER_TRAIN:
-		case PED_EXIT_TRAIN:
-		case PED_CARJACK:
-		case PED_DRAG_FROM_CAR:
-		case PED_ENTER_CAR:
-		case PED_STEAL_CAR:
-		case PED_EXIT_CAR:
-			ClearWeaponTarget();
-			break;
-		case PED_ARRESTED:
-			if (m_nLastPedState == PED_DRAG_FROM_CAR && m_pVehicleAnim)
-				BeingDraggedFromCar();
-			break;
-	}
-	if (padUsed && IsPedShootable()) {
-		ProcessWeaponSwitch(padUsed);
-		GetWeapon()->Update(m_audioEntityId);
-	}
-	ProcessAnimGroups();
-	if (padUsed) {
-		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FOLLOWPED
-			&& TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_BEHIND) {
-
-			m_lookTimer = 0;
-			float camAngle = CGeneral::LimitRadianAngle(TheCamera.Cams[TheCamera.ActiveCam].Front.Heading());
-			float angleBetweenPlayerAndCam = Abs(camAngle - m_fRotationCur);
-			if (m_nPedState != PED_ATTACK
-				&& angleBetweenPlayerAndCam > DEGTORAD(30.0f) && angleBetweenPlayerAndCam < DEGTORAD(330.0f)) {
-
-				if (angleBetweenPlayerAndCam > DEGTORAD(150.0f) && angleBetweenPlayerAndCam < DEGTORAD(210.0f)) {
-					float rightTurnAngle = CGeneral::LimitRadianAngle(m_fRotationCur - DEGTORAD(150.0f));
-					float leftTurnAngle = CGeneral::LimitRadianAngle(DEGTORAD(150.0f) + m_fRotationCur);
-					if (m_fLookDirection != 999999.0f) {
-						if (Abs(rightTurnAngle - m_fLookDirection) < Abs(leftTurnAngle - m_fLookDirection))
-							camAngle = rightTurnAngle;
-						else
-							camAngle = leftTurnAngle;
-					} else {
-						camAngle = rightTurnAngle;
-					}
-				}
-				SetLookFlag(camAngle, true);
-				SetLookTimer(CTimer::GetTimeStepInMilliseconds() * 5.0f);
-			} else {
-				ClearLookFlag();
-			}
-		}
-	}
-	if (m_nMoveState == PEDMOVE_SPRINT && bIsLooking) {
-		ClearLookFlag();
-		SetLookTimer(250);
-	}
-
-	if (m_vecMoveSpeed.Magnitude2D() < 0.1f) {
-		if (m_nSpeedTimer) {
-			if (CTimer::GetTimeInMilliseconds() > m_nSpeedTimer)
-				m_bSpeedTimerFlag = true;
-		} else {
-			m_nSpeedTimer = CTimer::GetTimeInMilliseconds() + 500;
-		}
-	} else {
-		m_nSpeedTimer = 0;
-		m_bSpeedTimerFlag = false;
-	}
-}
-
-#include <new>
-
-class CPlayerPed_ : public CPlayerPed
-{
-public:
-	CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); }
-	void dtor(void) { CPlayerPed::~CPlayerPed(); }
-	void SetMoveAnim_(void) { CPlayerPed::SetMoveAnim(); }
-	void ProcessControl_(void) { CPlayerPed::ProcessControl(); }
-};
-
-STARTPATCHES
-	InjectHook(0x4EF7E0, &CPlayerPed_::ctor, PATCH_JUMP);
-	InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP);
-	InjectHook(0x4F3760, &CPlayerPed_::SetMoveAnim_, PATCH_JUMP);
-	InjectHook(0x4EFD90, &CPlayerPed_::ProcessControl_, PATCH_JUMP);
-	InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP);
-	InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP);
-	InjectHook(0x4F36C0, &CPlayerPed::GetPlayerInfoForThisPlayerPed, PATCH_JUMP);
-	InjectHook(0x4F2560, &CPlayerPed::MakeChangesForNewWeapon, PATCH_JUMP);
-	InjectHook(0x4F07C0, &CPlayerPed::ReApplyMoveAnims, PATCH_JUMP);
-	InjectHook(0x4F0880, &CPlayerPed::SetRealMoveAnim, PATCH_JUMP);
-	InjectHook(0x4F1810, &CPlayerPed::PlayerControlFighter, PATCH_JUMP);
-	InjectHook(0x4F1340, &CPlayerPed::RestoreSprintEnergy, PATCH_JUMP);
-	InjectHook(0x4F1380, &CPlayerPed::DoWeaponSmoothSpray, PATCH_JUMP);
-	InjectHook(0x4F36E0, &CPlayerPed::DoStuffToGoOnFire, PATCH_JUMP);
-	InjectHook(0x4F3350, &CPlayerPed::DoesTargetHaveToBeBroken, PATCH_JUMP);
-	InjectHook(0x4F31D0, &CPlayerPed::RunningLand, PATCH_JUMP);
-	InjectHook(0x4F2D00, &CPlayerPed::IsThisPedAttackingPlayer, PATCH_JUMP);
-	InjectHook(0x4F1CF0, &CPlayerPed::PlayerControlSniper, PATCH_JUMP);
-	InjectHook(0x4F2310, &CPlayerPed::ProcessWeaponSwitch, PATCH_JUMP);
-	InjectHook(0x4F1DF0, &CPlayerPed::PlayerControlM16, PATCH_JUMP);
-	InjectHook(0x4F3460, &CPlayerPed::KeepAreaAroundPlayerClear, PATCH_JUMP);
-	InjectHook(0x4F1970, &CPlayerPed::PlayerControl1stPersonRunAround, PATCH_JUMP);
-	InjectHook(0x4F1EF0, &CPlayerPed::ProcessPlayerWeapon, PATCH_JUMP);
-	InjectHook(0x4F2640, &CPlayerPed::ProcessAnimGroups, PATCH_JUMP);
-ENDPATCHES
+#include "common.h"
+#include "patcher.h"
+#include "PlayerPed.h"
+#include "Wanted.h"
+#include "Fire.h"
+#include "DMAudio.h"
+#include "Pad.h"
+#include "Camera.h"
+#include "WeaponEffects.h"
+#include "ModelIndices.h"
+#include "World.h"
+#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
+#include "General.h"
+#include "Pools.h"
+#include "Darkel.h"
+#include "CarCtrl.h"
+
+#define PAD_MOVE_TO_GAME_WORLD_MOVE 60.0f
+
+CPlayerPed::~CPlayerPed()
+{
+	delete m_pWanted;
+}
+
+CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1)
+{
+	m_fMoveSpeed = 0.0f;
+	SetModelIndex(MI_PLAYER);
+	SetInitialState();
+
+	m_pWanted = new CWanted();
+	m_pWanted->Initialise();
+	m_pArrestingCop = nil;
+	m_currentWeapon = WEAPONTYPE_UNARMED;
+	m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+	m_nSpeedTimer = 0;
+	m_bSpeedTimerFlag = false;
+	m_pPointGunAt = nil;
+	m_nPedState = PED_IDLE;
+	m_fMaxStamina = 150.0f;
+	m_fCurrentStamina = m_fMaxStamina;
+	m_fStaminaProgress = 0.0f;
+	m_nEvadeAmount = 0;
+	field_1367 = 0;
+	m_nShotDelay = 0;
+	field_1376 = 0.0f;
+	m_bHaveTargetSelected = false;
+	m_bHasLockOnTarget = false;
+	m_bCanBeDamaged = true;
+	m_fWalkAngle = 0.0f;
+	m_fFPSMoveHeading = 0.0f;
+	m_nTargettableObjects[0] = m_nTargettableObjects[1] = m_nTargettableObjects[2] = m_nTargettableObjects[3] = -1;
+	field_1413 = 0;
+	for (int i = 0; i < 6; i++) {
+		m_vecSafePos[i] = CVector(0.0f, 0.0f, 0.0f);
+		m_pPedAtSafePos[i] = nil;
+	}
+}
+
+void CPlayerPed::ClearWeaponTarget()
+{
+	if (m_nPedType == PEDTYPE_PLAYER1) {
+		m_pPointGunAt = nil;
+		TheCamera.ClearPlayerWeaponMode();
+		CWeaponEffects::ClearCrossHair();
+	}
+ 	ClearPointGunAt();
+}
+
+void
+CPlayerPed::SetWantedLevel(int32 level)
+{
+	m_pWanted->SetWantedLevel(level);
+}
+
+void
+CPlayerPed::SetWantedLevelNoDrop(int32 level)
+{
+	m_pWanted->SetWantedLevelNoDrop(level);
+}
+
+void
+CPlayerPed::MakeObjectTargettable(int32 handle)
+{
+	for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
+		if (
+#ifdef FIX_BUGS
+			m_nTargettableObjects[i] == -1 ||
+#endif
+			CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]) == nil) {
+			m_nTargettableObjects[i] = handle;
+			return;
+		}
+	}
+}
+
+// I don't know the actual purpose of parameter
+void
+CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity)
+{
+	if (m_pedStats->m_temper < 52) {
+		m_pedStats->m_temper++;
+	} else {
+		if (annoyedByPassingEntity) {
+			if (m_pedStats->m_temper < 55) {
+				m_pedStats->m_temper++;
+			} else {
+				m_pedStats->m_temper = 46;
+			}
+		}
+	}
+}
+
+void
+CPlayerPed::ClearAdrenaline(void)
+{
+	if (m_bAdrenalineActive && m_nAdrenalineTime != 0) {
+		m_nAdrenalineTime = 0;
+		CTimer::SetTimeScale(1.0f);
+	}
+}
+
+CPlayerInfo *
+CPlayerPed::GetPlayerInfoForThisPlayerPed()
+{
+	if (CWorld::Players[0].m_pPed == this)
+		return &CWorld::Players[0];
+
+	return nil;
+}
+
+void
+CPlayerPed::SetupPlayerPed(int32 index)
+{
+	CPlayerPed *player = new CPlayerPed();
+	CWorld::Players[index].m_pPed = player;
+
+	player->SetOrientation(0.0f, 0.0f, 0.0f);
+
+	CWorld::Add(player);
+	player->m_wepAccuracy = 100;
+}
+
+void
+CPlayerPed::DeactivatePlayerPed(int32 index)
+{
+	CWorld::Remove(CWorld::Players[index].m_pPed);
+}
+
+void
+CPlayerPed::ReactivatePlayerPed(int32 index)
+{
+	CWorld::Add(CWorld::Players[index].m_pPed);
+}
+
+void
+CPlayerPed::UseSprintEnergy(void)
+{
+	if (m_fCurrentStamina > -150.0f && !CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint
+		&& !m_bAdrenalineActive) {
+		m_fCurrentStamina = m_fCurrentStamina - CTimer::GetTimeStep();
+		m_fStaminaProgress = m_fStaminaProgress + CTimer::GetTimeStep();
+	}
+
+	if (m_fStaminaProgress >= 500.0f) {
+		m_fStaminaProgress = 0;
+		if (m_fMaxStamina < 1000.0f)
+			m_fMaxStamina += 10.0f;
+	}
+}
+
+void
+CPlayerPed::MakeChangesForNewWeapon(int8 weapon)
+{
+	if (m_nPedState == PED_SNIPER_MODE) {
+		RestorePreviousState();
+		TheCamera.ClearPlayerWeaponMode();
+	}
+	SetCurrentWeapon(weapon);
+
+	GetWeapon()->m_nAmmoInClip = min(GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition);
+
+	if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAim))
+		ClearWeaponTarget();
+
+	CAnimBlendAssociation *weaponAnim = RpAnimBlendClumpGetAssociation(GetClump(), CWeaponInfo::GetWeaponInfo(WEAPONTYPE_SNIPERRIFLE)->m_AnimToPlay);
+	if (weaponAnim) {
+		weaponAnim->SetRun();
+		weaponAnim->flags |= ASSOC_FADEOUTWHENDONE;
+	}
+	TheCamera.ClearPlayerWeaponMode();
+}
+
+void
+CPlayerPed::ReApplyMoveAnims(void)
+{
+	static AnimationId moveAnims[] = { ANIM_WALK, ANIM_RUN, ANIM_SPRINT, ANIM_IDLE_STANCE, ANIM_WALK_START };
+
+	for(int i = 0; i < ARRAY_SIZE(moveAnims); i++) {
+		CAnimBlendAssociation *curMoveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), moveAnims[i]);
+		if (curMoveAssoc) {
+			if (strcmp(CAnimManager::GetAnimAssociation(m_animGroup, moveAnims[i])->hierarchy->name, curMoveAssoc->hierarchy->name) != 0) {
+				CAnimBlendAssociation *newMoveAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, moveAnims[i]);
+				newMoveAssoc->blendDelta = curMoveAssoc->blendDelta;
+				newMoveAssoc->blendAmount = curMoveAssoc->blendAmount;
+				curMoveAssoc->blendDelta = -1000.0f;
+				curMoveAssoc->flags |= ASSOC_DELETEFADEDOUT;
+			}
+		}
+	}
+}
+
+void
+CPlayerPed::SetInitialState(void)
+{
+	m_bAdrenalineActive = false;
+	m_nAdrenalineTime = 0;
+	CTimer::SetTimeStep(1.0f);
+	m_pSeekTarget = nil;
+	m_vecSeekPos = { 0.0f, 0.0f, 0.0f };
+	m_fleeFromPosX = 0.0f;
+	m_fleeFromPosY = 0.0f;
+	m_fleeFrom = nil;
+	m_fleeTimer = 0;
+	m_objective = OBJECTIVE_NONE;
+	m_prevObjective = OBJECTIVE_NONE;
+	bUsesCollision = true;
+	ClearAimFlag();
+	ClearLookFlag();
+	bIsPointingGunAt = false;
+	bRenderPedInCar = true;
+	if (m_pFire)
+		m_pFire->Extinguish();
+	RpAnimBlendClumpRemoveAllAssociations(GetClump());
+	m_nPedState = PED_IDLE;
+	SetMoveState(PEDMOVE_STILL);
+	m_nLastPedState = PED_NONE;
+	m_animGroup = ASSOCGRP_PLAYER;
+	m_fMoveSpeed = 0.0f;
+	m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+	m_nEvadeAmount = 0;
+	m_pEvadingFrom = nil;
+	bIsPedDieAnimPlaying = false;
+	SetRealMoveAnim();
+	m_bCanBeDamaged = true;
+	m_pedStats->m_temper = 50;
+	m_fWalkAngle = 0.0f;
+}
+
+void
+CPlayerPed::SetRealMoveAnim(void)
+{
+	CAnimBlendAssociation *curWalkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK);
+	CAnimBlendAssociation *curRunAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN);
+	CAnimBlendAssociation *curSprintAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT);
+	CAnimBlendAssociation *curWalkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
+	CAnimBlendAssociation *curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
+	CAnimBlendAssociation *curRunStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
+	CAnimBlendAssociation *curRunStopRAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
+	if (bResetWalkAnims) {
+		if (curWalkAssoc)
+			curWalkAssoc->SetCurrentTime(0.0f);
+		if (curRunAssoc)
+			curRunAssoc->SetCurrentTime(0.0f);
+		if (curSprintAssoc)
+			curSprintAssoc->SetCurrentTime(0.0f);
+		bResetWalkAnims = false;
+	}
+
+	if (!curIdleAssoc)
+		curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+	if (!curIdleAssoc)
+		curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
+
+	if ((!curRunStopAssoc || !(curRunStopAssoc->IsRunning())) && (!curRunStopRAssoc || !(curRunStopRAssoc->IsRunning()))) {
+
+		if (curRunStopAssoc && curRunStopAssoc->blendDelta >= 0.0f || curRunStopRAssoc && curRunStopRAssoc->blendDelta >= 0.0f) {
+			if (curRunStopAssoc) {
+				curRunStopAssoc->flags |= ASSOC_DELETEFADEDOUT;
+				curRunStopAssoc->blendAmount = 1.0f;
+				curRunStopAssoc->blendDelta = -8.0f;
+			} else if (curRunStopRAssoc) {
+				curRunStopRAssoc->flags |= ASSOC_DELETEFADEDOUT;
+				curRunStopRAssoc->blendAmount = 1.0f;
+				curRunStopRAssoc->blendDelta = -8.0f;
+			}
+			
+			RestoreHeadingRate();
+			if (!curIdleAssoc) {
+				if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
+						nil, true, false, false, false, false, false)) {
+					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 8.0f);
+
+				} else {
+					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
+				}
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
+			}
+			curIdleAssoc->blendAmount = 0.0f;
+			curIdleAssoc->blendDelta = 8.0f;
+
+		} else if (m_fMoveSpeed == 0.0f && !curSprintAssoc) {
+			if (!curIdleAssoc) {
+				if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
+						nil, true, false, false, false, false, false)) {
+					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
+					
+				} else {
+					curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+				}
+
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
+			}
+
+			if (m_fCurrentStamina > 0.0f && curIdleAssoc->animId == ANIM_IDLE_TIRED) {
+				CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+
+			} else if (m_nPedState != PED_FIGHT) {
+				if (m_fCurrentStamina < 0.0f && curIdleAssoc->animId != ANIM_IDLE_TIRED
+					&& !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f, nil, true, false, false, false, false, false)) {
+					CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
+
+				} else if (curIdleAssoc->animId != ANIM_IDLE_STANCE) {
+					CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+				}
+			}
+
+			m_nMoveState = PEDMOVE_STILL;
+		} else {
+			if (curIdleAssoc) {
+				if (curWalkStartAssoc) {
+					curWalkStartAssoc->blendAmount = 1.0f;
+					curWalkStartAssoc->blendDelta = 0.0f;
+				} else {
+					curWalkStartAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK_START);
+				}
+				if (curWalkAssoc)
+					curWalkAssoc->SetCurrentTime(0.0f);
+				if (curRunAssoc)
+					curRunAssoc->SetCurrentTime(0.0f);
+
+				delete curIdleAssoc;
+				delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+				delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
+				delete curSprintAssoc;
+
+				curSprintAssoc = nil;
+				m_nMoveState = PEDMOVE_WALK;
+			}
+			if (curRunStopAssoc) {
+				delete curRunStopAssoc;
+				RestoreHeadingRate();
+			}
+			if (curRunStopRAssoc) {
+				delete curRunStopRAssoc;
+				RestoreHeadingRate();
+			}
+			if (!curWalkAssoc) {
+				curWalkAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK);
+				curWalkAssoc->blendAmount = 0.0f;
+			}
+			if (!curRunAssoc) {
+				curRunAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_RUN);
+				curRunAssoc->blendAmount = 0.0f;
+			}
+			if (curWalkStartAssoc && !(curWalkStartAssoc->IsRunning())) {
+				delete curWalkStartAssoc;
+				curWalkStartAssoc = nil;
+				curWalkAssoc->SetRun();
+				curRunAssoc->SetRun();
+			}
+			if (m_nMoveState == PEDMOVE_SPRINT) {
+				if (m_fCurrentStamina < 0.0f && (m_fCurrentStamina <= -150.0f || !curSprintAssoc || curSprintAssoc->blendDelta < 0.0f))
+					m_nMoveState = PEDMOVE_STILL;
+
+				if (curWalkStartAssoc)
+					m_nMoveState = PEDMOVE_STILL;
+			}
+
+			if (curSprintAssoc && (m_nMoveState != PEDMOVE_SPRINT || m_fMoveSpeed < 0.4f)) {
+				if (curSprintAssoc->blendAmount == 0.0f) {
+					curSprintAssoc->blendDelta = -1000.0f;
+					curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+
+				} else if (curSprintAssoc->blendDelta >= 0.0f || curSprintAssoc->blendAmount >= 0.8f) {
+					if (m_fMoveSpeed < 0.4f) {
+						AnimationId runStopAnim;
+						if (curSprintAssoc->currentTime / curSprintAssoc->hierarchy->totalLength < 0.5) // double
+							runStopAnim = ANIM_RUN_STOP;
+						else
+							runStopAnim = ANIM_RUN_STOP_R;
+						CAnimBlendAssociation* newRunStopAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, runStopAnim);
+						newRunStopAssoc->blendAmount = 1.0f;
+						newRunStopAssoc->SetDeleteCallback(RestoreHeadingRateCB, this);
+						m_headingRate = 0.0f;
+						curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+						curSprintAssoc->blendDelta = -1000.0f;
+						curWalkAssoc->flags &= ~ASSOC_RUNNING;
+						curWalkAssoc->blendAmount = 0.0f;
+						curWalkAssoc->blendDelta = 0.0f;
+						curRunAssoc->flags &= ~ASSOC_RUNNING;
+						curRunAssoc->blendAmount = 0.0f;
+						curRunAssoc->blendDelta = 0.0f;
+					} else if (curSprintAssoc->blendDelta >= 0.0f) {
+
+						// Stop sprinting when tired
+						curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
+						curSprintAssoc->blendDelta = -1.0f;
+						curRunAssoc->blendDelta = 1.0f;
+					}
+				} else if (m_fMoveSpeed < 1.0f) {
+					curSprintAssoc->blendDelta = -8.0f;
+					curRunAssoc->blendDelta = 8.0f;
+				}
+			} else if (curWalkStartAssoc) {
+				curWalkAssoc->flags &= ~ASSOC_RUNNING;
+				curRunAssoc->flags &= ~ASSOC_RUNNING;
+				curWalkAssoc->blendAmount = 0.0f;
+				curRunAssoc->blendAmount = 0.0f;
+
+			} else if (m_nMoveState == PEDMOVE_SPRINT) {
+				if (curSprintAssoc) {
+					if (curSprintAssoc->blendDelta < 0.0f) {
+						curSprintAssoc->blendDelta = 2.0f;
+						curRunAssoc->blendDelta = -2.0f;
+					}
+				} else {
+					curWalkAssoc->blendAmount = 0.0f;
+					curRunAssoc->blendAmount = 1.0f;
+					curSprintAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_SPRINT, 2.0f);
+				}
+				UseSprintEnergy();
+			} else {
+				if (m_fMoveSpeed < 1.0f) {
+					curWalkAssoc->blendAmount = 1.0f;
+					curRunAssoc->blendAmount = 0.0f;
+					m_nMoveState = PEDMOVE_WALK;
+				} else if (m_fMoveSpeed < 2.0f) {
+					curWalkAssoc->blendAmount = 2.0f - m_fMoveSpeed;
+					curRunAssoc->blendAmount = m_fMoveSpeed - 1.0f;
+					m_nMoveState = PEDMOVE_RUN;
+				} else {
+					curWalkAssoc->blendAmount = 0.0f;
+					curRunAssoc->blendAmount = 1.0f;
+					m_nMoveState = PEDMOVE_RUN;
+				}
+			}
+		}
+	}
+	if (m_bAdrenalineActive) {
+		if (CTimer::GetTimeInMilliseconds() > m_nAdrenalineTime) {
+			m_bAdrenalineActive = false;
+			CTimer::SetTimeScale(1.0f);
+			if (curWalkStartAssoc)
+				curWalkStartAssoc->speed = 1.0f;
+			if (curWalkAssoc)
+				curWalkAssoc->speed = 1.0f;
+			if (curRunAssoc)
+				curRunAssoc->speed = 1.0f;
+			if (curSprintAssoc)
+				curSprintAssoc->speed = 1.0f;
+		} else {
+			CTimer::SetTimeScale(1.0f / 3);
+			if (curWalkStartAssoc)
+				curWalkStartAssoc->speed = 2.0f;
+			if (curWalkAssoc)
+				curWalkAssoc->speed = 2.0f;
+			if (curRunAssoc)
+				curRunAssoc->speed = 2.0f;
+			if (curSprintAssoc)
+				curSprintAssoc->speed = 2.0f;
+		}
+	}
+}
+
+void
+CPlayerPed::RestoreSprintEnergy(float restoreSpeed)
+{
+	if (m_fCurrentStamina < m_fMaxStamina)
+		m_fCurrentStamina += restoreSpeed * CTimer::GetTimeStep() * 0.5f;
+}
+
+bool
+CPlayerPed::DoWeaponSmoothSpray(void)
+{
+	if (m_nPedState == PED_ATTACK && !m_pPointGunAt) {
+		eWeaponType weapon = GetWeapon()->m_eWeaponType;
+		if (weapon == WEAPONTYPE_FLAMETHROWER || weapon == WEAPONTYPE_COLT45 || weapon == WEAPONTYPE_UZI || weapon == WEAPONTYPE_SHOTGUN || 
+			weapon == WEAPONTYPE_AK47 || weapon == WEAPONTYPE_M16 || weapon == WEAPONTYPE_HELICANNON)
+			return true;
+	}
+	return false;
+}
+
+void
+CPlayerPed::DoStuffToGoOnFire(void)
+{
+	if (m_nPedState == PED_SNIPER_MODE)
+		TheCamera.ClearPlayerWeaponMode();
+}
+
+bool
+CPlayerPed::DoesTargetHaveToBeBroken(CVector target, CWeapon *weaponUsed)
+{
+	CVector distVec = target - GetPosition();
+
+	if (distVec.Magnitude() > CWeaponInfo::GetWeaponInfo(weaponUsed->m_eWeaponType)->m_fRange)
+		return true;
+
+	if (weaponUsed->m_eWeaponType != WEAPONTYPE_SHOTGUN && weaponUsed->m_eWeaponType != WEAPONTYPE_AK47)
+		return false;
+
+	distVec.Normalise();
+
+	if (DotProduct(distVec,GetForward()) < 0.4f)
+		return true;
+
+	return false;
+}
+
+// Cancels landing anim while running & jumping? I think
+void
+CPlayerPed::RunningLand(CPad *padUsed)
+{
+	CAnimBlendAssociation *landAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_LAND);
+	if (landAssoc && landAssoc->currentTime == 0.0f && m_fMoveSpeed > 1.5f
+		&& padUsed && (padUsed->GetPedWalkLeftRight() != 0.0f || padUsed->GetPedWalkUpDown() != 0.0f)) {
+
+		landAssoc->blendDelta = -1000.0f;
+		landAssoc->flags |= ASSOC_DELETEFADEDOUT;
+
+		CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_JUMP_LAND)->SetFinishCallback(FinishJumpCB, this);
+
+		if (m_nPedState == PED_JUMP)
+			RestorePreviousState();
+	}
+}
+
+bool
+CPlayerPed::IsThisPedAttackingPlayer(CPed *suspect)
+{
+	if (suspect->m_pPointGunAt == this)
+		return true;
+
+	switch (suspect->m_objective) {
+		case OBJECTIVE_KILL_CHAR_ON_FOOT:
+		case OBJECTIVE_KILL_CHAR_ANY_MEANS:
+			if (suspect->m_pedInObjective == this)
+				return true;
+
+			break;
+		default:
+			break;
+	}
+	return false;
+}
+
+void
+CPlayerPed::PlayerControlSniper(CPad *padUsed)
+{
+	ProcessWeaponSwitch(padUsed);
+	TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f;
+
+	if (!padUsed->GetTarget()) {
+		RestorePreviousState();
+		TheCamera.ClearPlayerWeaponMode();
+	}
+
+	if (padUsed->WeaponJustDown()) {
+		CVector firePos(0.0f, 0.0f, 0.6f);
+		firePos = GetMatrix() * firePos;
+		GetWeapon()->Fire(this, &firePos);
+	}
+	GetWeapon()->Update(m_audioEntityId);
+}
+
+// I think R* also used goto in here.
+void
+CPlayerPed::ProcessWeaponSwitch(CPad *padUsed)
+{
+	if (CDarkel::FrenzyOnGoing())
+		goto switchDetectDone;
+
+	if (padUsed->CycleWeaponRightJustDown() && !m_pPointGunAt) {
+
+		if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
+			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON_RUNABOUT
+			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
+			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER_RUNABOUT
+			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER
+			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER_RUNABOUT) {
+
+			for (m_nSelectedWepSlot = m_currentWeapon + 1; m_nSelectedWepSlot < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; ++m_nSelectedWepSlot) {
+				if (HasWeapon(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) {
+					goto switchDetectDone;
+				}
+			}
+			m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+		}
+	} else if (padUsed->CycleWeaponLeftJustDown() && !m_pPointGunAt) {
+		if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
+			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
+			&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER) {
+
+			for (m_nSelectedWepSlot = m_currentWeapon - 1; ; --m_nSelectedWepSlot) {
+				if (m_nSelectedWepSlot < WEAPONTYPE_UNARMED)
+					m_nSelectedWepSlot = WEAPONTYPE_DETONATOR;
+
+				if (HasWeapon(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) {
+					goto switchDetectDone;
+				}
+			}
+		}
+	} else if (CWeaponInfo::GetWeaponInfo((eWeaponType)m_currentWeapon)->m_eWeaponFire != WEAPON_FIRE_MELEE) {
+		if (GetWeapon(m_currentWeapon).m_nAmmoTotal <= 0) {
+			if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
+				&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
+				&& TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER) {
+
+				for (m_nSelectedWepSlot = m_currentWeapon - 1; m_nSelectedWepSlot >= 0; --m_nSelectedWepSlot) {
+					if (m_nSelectedWepSlot == WEAPONTYPE_BASEBALLBAT && HasWeapon(WEAPONTYPE_BASEBALLBAT)
+						|| GetWeapon(m_nSelectedWepSlot).m_nAmmoTotal > 0 && m_nSelectedWepSlot != WEAPONTYPE_MOLOTOV && m_nSelectedWepSlot != WEAPONTYPE_GRENADE) {
+						goto switchDetectDone;
+					}
+				}
+				m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+			}
+		}
+	}
+
+switchDetectDone:
+	if (m_nSelectedWepSlot != m_currentWeapon) {
+		if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN && m_nPedState != PED_FIGHT)
+			MakeChangesForNewWeapon(m_nSelectedWepSlot);
+	}
+}
+
+void
+CPlayerPed::PlayerControlM16(CPad *padUsed)
+{
+	ProcessWeaponSwitch(padUsed);
+	TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f;
+
+	if (!padUsed->GetTarget()) {
+		RestorePreviousState();
+		TheCamera.ClearPlayerWeaponMode();
+	}
+
+	if (padUsed->GetWeapon()) {
+		CVector firePos(0.0f, 0.0f, 0.6f);
+		firePos = GetMatrix() * firePos;
+		GetWeapon()->Fire(this, &firePos);
+	}
+	GetWeapon()->Update(m_audioEntityId);
+}
+
+void
+CPlayerPed::PlayerControlFighter(CPad *padUsed)
+{
+	float leftRight = padUsed->GetPedWalkLeftRight();
+	float upDown = padUsed->GetPedWalkUpDown();
+	float padMove = CVector2D(leftRight, upDown).Magnitude();
+
+	if (padMove > 0.0f) {
+		m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown) - TheCamera.Orientation;
+		m_takeAStepAfterAttack = padMove > 2 * PAD_MOVE_TO_GAME_WORLD_MOVE;
+		if (padUsed->GetSprint() && padMove > 1 * PAD_MOVE_TO_GAME_WORLD_MOVE)
+			bIsAttacking = false;
+	}
+
+	if (!CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy && padUsed->JumpJustDown()) {
+		if (m_nEvadeAmount != 0 && m_pEvadingFrom) {
+			SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1);
+			m_nEvadeAmount = 0;
+			m_pEvadingFrom = nil;
+		} else {
+			SetJump();
+		}
+	}
+}
+
+void
+CPlayerPed::PlayerControl1stPersonRunAround(CPad *padUsed)
+{
+	float leftRight = padUsed->GetPedWalkLeftRight();
+	float upDown = padUsed->GetPedWalkUpDown();
+	float padMove = CVector2D(leftRight, upDown).Magnitude();
+	float padMoveInGameUnit = padMove / PAD_MOVE_TO_GAME_WORLD_MOVE;
+	if (padMoveInGameUnit > 0.0f) {
+#ifdef FREE_CAM
+		if (!CCamera::bFreeCam)
+			m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation);
+		else
+			m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown) - TheCamera.Orientation;
+#else
+		m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation);
+#endif
+		m_fMoveSpeed = min(padMoveInGameUnit, 0.07f * CTimer::GetTimeStep() + m_fMoveSpeed);
+	} else {
+		m_fMoveSpeed = 0.0f;
+	}
+
+	if (m_nPedState == PED_JUMP) {
+		if (bIsInTheAir) {
+			if (bUsesCollision && !bHitSteepSlope &&
+				(!bHitSomethingLastFrame || m_vecDamageNormal.z > 0.6f)
+				&& m_fDistanceTravelled < CTimer::GetTimeStep() * 0.02 && m_vecMoveSpeed.MagnitudeSqr() < 0.01f) {
+
+				float angleSin = Sin(m_fRotationCur); // originally sin(DEGTORAD(RADTODEG(m_fRotationCur))) o_O
+				float angleCos = Cos(m_fRotationCur);
+				ApplyMoveForce(-angleSin * 3.0f, 3.0f * angleCos, 0.05f);
+			}
+		} else if (bIsLanding) {
+			m_fMoveSpeed = 0.0f;
+		}
+	}
+	if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
+		&& padUsed->GetSprint()) {
+		m_nMoveState = PEDMOVE_SPRINT;
+	}
+	if (m_nPedState != PED_FIGHT)
+		SetRealMoveAnim();
+
+	if (!bIsInTheAir && !(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
+		&& padUsed->JumpJustDown() && m_nPedState != PED_JUMP) {
+		ClearAttack();
+		ClearWeaponTarget();
+		if (m_nEvadeAmount != 0 && m_pEvadingFrom) {
+			SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1);
+			m_nEvadeAmount = 0;
+			m_pEvadingFrom = nil;
+		} else {
+			SetJump();
+		}
+	}
+}
+
+void
+CPlayerPed::KeepAreaAroundPlayerClear(void)
+{
+	BuildPedLists();
+	for (int i = 0; i < m_numNearPeds; ++i) {
+		CPed *nearPed = m_nearPeds[i];
+		if (nearPed->CharCreatedBy == RANDOM_CHAR && !nearPed->DyingOrDead()) {
+			if (nearPed->GetIsOnScreen()) {
+				if (nearPed->m_objective == OBJECTIVE_NONE) {
+					nearPed->SetFindPathAndFlee(this, 5000, true);
+				} else {
+					if (nearPed->EnteringCar())
+						nearPed->QuitEnteringCar();
+
+					nearPed->ClearObjective();
+				}
+			} else {
+				nearPed->FlagToDestroyWhenNextProcessed();
+			}
+		}
+	}
+	CVector playerPos = (InVehicle() ? m_pMyVehicle->GetPosition() : GetPosition());
+
+	CVector pos = GetPosition();
+	int16 lastVehicle;
+	CEntity *vehicles[8];
+	CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false);
+
+	for (int i = 0; i < lastVehicle; i++) {
+		CVehicle *veh = (CVehicle*)vehicles[i];
+		if (veh->VehicleCreatedBy != MISSION_VEHICLE) {
+			if (veh->m_status != STATUS_PLAYER && veh->m_status != STATUS_PLAYER_DISABLED) {
+				if ((veh->GetPosition() - playerPos).MagnitudeSqr() > 25.0f) {
+					veh->AutoPilot.m_nTempAction = TEMPACT_WAIT;
+					veh->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 5000;
+				} else {
+					if (DotProduct2D(playerPos - veh->GetPosition(), veh->GetForward()) > 0.0f)
+						veh->AutoPilot.m_nTempAction = TEMPACT_REVERSE;
+					else
+						veh->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD;
+
+					veh->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000;
+				}
+				CCarCtrl::PossiblyRemoveVehicle(veh);
+			}
+		}
+	}
+}
+
+void
+CPlayerPed::EvaluateNeighbouringTarget(CEntity *candidate, CEntity **targetPtr, float *lastCloseness, float distLimit, float angleOffset, bool lookToLeft)
+{
+	CVector distVec = candidate->GetPosition() - GetPosition();
+	if (distVec.Magnitude2D() <= distLimit) {
+		if (!DoesTargetHaveToBeBroken(candidate->GetPosition(), GetWeapon())) {
+#ifdef VC_PED_PORTS
+			float angleBetweenUs = CGeneral::GetATanOfXY(candidate->GetPosition().x - TheCamera.GetPosition().x,
+															candidate->GetPosition().y - TheCamera.GetPosition().y);
+#else
+			float angleBetweenUs = CGeneral::GetATanOfXY(distVec.x, distVec.y);
+#endif
+			angleBetweenUs = CGeneral::LimitAngle(angleBetweenUs - angleOffset);
+			float closeness;
+			if (lookToLeft) {
+				closeness = angleBetweenUs > 0.0f ? -Abs(angleBetweenUs) : -100000.0f;
+			} else {
+				closeness = angleBetweenUs > 0.0f ? -100000.0f : -Abs(angleBetweenUs);
+			}
+
+			if (closeness > *lastCloseness) {
+				*targetPtr = candidate;
+				*lastCloseness = closeness;
+			}
+		}
+	}
+}
+
+void
+CPlayerPed::EvaluateTarget(CEntity *candidate, CEntity **targetPtr, float *lastCloseness, float distLimit, float angleOffset, bool priority)
+{
+	CVector distVec = candidate->GetPosition() - GetPosition();
+	float dist = distVec.Magnitude2D();
+	if (dist <= distLimit) {
+		if (!DoesTargetHaveToBeBroken(candidate->GetPosition(), GetWeapon())) {
+			float angleBetweenUs = CGeneral::GetATanOfXY(distVec.x, distVec.y);
+			angleBetweenUs = CGeneral::LimitAngle(angleBetweenUs - angleOffset);
+
+			float closeness = -dist - 5.0f * Abs(angleBetweenUs);
+			if (priority) {
+				closeness += 5.0f;
+			}
+
+			if (closeness > *lastCloseness) {
+				*targetPtr = candidate;
+				*lastCloseness = closeness;
+			}
+		}
+	}
+}
+
+bool
+CPlayerPed::FindNextWeaponLockOnTarget(CEntity *previousTarget, bool lookToLeft)
+{
+	CEntity *nextTarget = nil;
+	float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
+	// nextTarget = nil;
+	float lastCloseness = -10000.0f;
+	// unused
+	// CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
+	CVector distVec = previousTarget->GetPosition() - GetPosition();
+	float referenceBeta = CGeneral::GetATanOfXY(distVec.x, distVec.y);
+
+	for (int h = CPools::GetPedPool()->GetSize() - 1; h >= 0; h--) {
+		CPed *pedToCheck = CPools::GetPedPool()->GetSlot(h);
+		if (pedToCheck) {
+			if (pedToCheck != FindPlayerPed() && pedToCheck != previousTarget) {
+				if (!pedToCheck->DyingOrDead() && !pedToCheck->bInVehicle
+					&& pedToCheck->m_leader != FindPlayerPed() && OurPedCanSeeThisOne(pedToCheck)) {
+
+					EvaluateNeighbouringTarget(pedToCheck, &nextTarget, &lastCloseness,
+						weaponRange, referenceBeta, lookToLeft);
+				}
+			}
+		}
+	}
+	for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
+		CObject *obj = CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]);
+		if (obj)
+			EvaluateNeighbouringTarget(obj, &nextTarget, &lastCloseness, weaponRange, referenceBeta, lookToLeft);
+	}
+	if (!nextTarget)
+		return false;
+
+	m_pPointGunAt = nextTarget;
+	if (nextTarget)
+		nextTarget->RegisterReference((CEntity**)&m_pPointGunAt);
+	SetPointGunAt(nextTarget);
+	return true;
+}
+
+bool
+CPlayerPed::FindWeaponLockOnTarget(void)
+{
+	CEntity *nextTarget = nil;
+	float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
+
+	if (m_pPointGunAt) {
+		CVector distVec = m_pPointGunAt->GetPosition() - GetPosition();
+		if (distVec.Magnitude2D() > weaponRange) {
+			m_pPointGunAt = nil;
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	// nextTarget = nil;
+	float lastCloseness = -10000.0f;
+	float referenceBeta = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
+	for (int h = CPools::GetPedPool()->GetSize() - 1; h >= 0; h--) {
+		CPed *pedToCheck = CPools::GetPedPool()->GetSlot(h);
+		if (pedToCheck) {
+			if (pedToCheck != FindPlayerPed()) {
+				if (!pedToCheck->DyingOrDead() && !pedToCheck->bInVehicle
+					&& pedToCheck->m_leader != FindPlayerPed() && OurPedCanSeeThisOne(pedToCheck)) {
+
+					EvaluateTarget(pedToCheck, &nextTarget, &lastCloseness,
+						weaponRange, referenceBeta, IsThisPedAttackingPlayer(pedToCheck));
+				}
+			}
+		}
+	}
+	for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
+		CObject *obj = CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]);
+		if (obj)
+			EvaluateTarget(obj, &nextTarget, &lastCloseness, weaponRange, referenceBeta, false);
+	}
+	if (!nextTarget)
+		return false;
+
+	m_pPointGunAt = nextTarget;
+	if (nextTarget)
+		nextTarget->RegisterReference((CEntity**)&m_pPointGunAt);
+	SetPointGunAt(nextTarget);
+	return true;
+}
+
+void
+CPlayerPed::ProcessAnimGroups(void)
+{
+	AssocGroupId groupToSet;
+	if ((m_fWalkAngle <= -DEGTORAD(50.0f) || m_fWalkAngle >= DEGTORAD(50.0f))
+		&& TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam()
+		&& CanStrafeOrMouseControl()) {
+
+		if (m_fWalkAngle >= -DEGTORAD(130.0f) && m_fWalkAngle <= DEGTORAD(130.0f)) {
+			if (m_fWalkAngle > 0.0f) {
+				if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
+					groupToSet = ASSOCGRP_ROCKETLEFT;
+				else
+					groupToSet = ASSOCGRP_PLAYERLEFT;
+			} else {
+				if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
+					groupToSet = ASSOCGRP_ROCKETRIGHT;
+				else
+					groupToSet = ASSOCGRP_PLAYERRIGHT;
+			}
+		} else {
+			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
+				groupToSet = ASSOCGRP_ROCKETBACK;
+			else
+				groupToSet = ASSOCGRP_PLAYERBACK;
+		}
+	} else {
+		if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) {
+			groupToSet = ASSOCGRP_PLAYERROCKET;
+		} else {
+			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) {
+				groupToSet = ASSOCGRP_PLAYERBBBAT;
+			} else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_COLT45 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UZI) {
+				if (!GetWeapon()->IsType2Handed()) {
+					groupToSet = ASSOCGRP_PLAYER;
+				} else {
+					groupToSet = ASSOCGRP_PLAYER2ARMED;
+				}
+			} else {
+				groupToSet = ASSOCGRP_PLAYER1ARMED;
+			}
+		}
+	}
+
+	if (m_animGroup != groupToSet) {
+		m_animGroup = groupToSet;
+		ReApplyMoveAnims();
+	}
+}
+
+void
+CPlayerPed::ProcessPlayerWeapon(CPad *padUsed)
+{
+	CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+	if (m_bHasLockOnTarget && !m_pPointGunAt) {
+		TheCamera.ClearPlayerWeaponMode();
+		CWeaponEffects::ClearCrossHair();
+		ClearPointGunAt();
+	}
+	if (!m_pFire) {
+		if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER ||
+			GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || GetWeapon()->m_eWeaponType == WEAPONTYPE_M16) {
+			if (padUsed->TargetJustDown()) {
+				SetStoredState();
+				m_nPedState = PED_SNIPER_MODE;
+#ifdef FREE_CAM
+				if (CCamera::bFreeCam && TheCamera.Cams[0].Using3rdPersonMouseCam()) {
+					m_fRotationCur = CGeneral::LimitRadianAngle(-TheCamera.Orientation);
+					SetHeading(m_fRotationCur);
+				}
+#endif
+				if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER)
+					TheCamera.SetNewPlayerWeaponMode(CCam::MODE_ROCKETLAUNCHER, 0, 0);
+				else if (GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE)
+					TheCamera.SetNewPlayerWeaponMode(CCam::MODE_SNIPER, 0, 0);
+				else
+					TheCamera.SetNewPlayerWeaponMode(CCam::MODE_M16_1STPERSON, 0, 0);
+
+				m_fMoveSpeed = 0.0f;
+				CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 1000.0f);
+			}
+			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER || GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE
+				|| TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON)
+				return;
+		}
+	}
+
+	if (padUsed->GetWeapon() && m_nMoveState != PEDMOVE_SPRINT) {
+		if (m_nSelectedWepSlot == m_currentWeapon) {
+			if (m_pPointGunAt) {
+#ifdef FREE_CAM
+				if (CCamera::bFreeCam && weaponInfo->m_eWeaponFire == WEAPON_FIRE_MELEE && m_fMoveSpeed < 1.0f)
+					StartFightAttack(padUsed->GetWeapon());
+				else
+#endif
+					SetAttack(m_pPointGunAt);
+			} else if (m_currentWeapon != WEAPONTYPE_UNARMED) {
+				if (m_nPedState == PED_ATTACK) {
+					if (padUsed->WeaponJustDown()) {
+						m_bHaveTargetSelected = true;
+					} else if (!m_bHaveTargetSelected) {
+						field_1376 += CTimer::GetTimeStepNonClipped();
+					}
+				} else {
+					field_1376 = 0.0f;
+					m_bHaveTargetSelected = false;
+				}
+				SetAttack(nil);
+			} else if (padUsed->WeaponJustDown()) {
+				if (m_fMoveSpeed < 1.0f)
+					StartFightAttack(padUsed->GetWeapon());
+				else
+					SetAttack(nil);
+			}
+		}
+	} else {
+		m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY;
+		if (m_nPedState == PED_ATTACK) {
+			m_bHaveTargetSelected = true;
+			bIsAttacking = false;
+		}
+	}
+
+#ifdef FREE_CAM
+	// Rotate player/arm when shooting. We don't have auto-rotation anymore
+	if (CCamera::m_bUseMouse3rdPerson && CCamera::bFreeCam &&
+		m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT) {
+
+		// Weapons except throwable and melee ones
+		if (weaponInfo->m_bCanAim || weaponInfo->m_b1stPerson || weaponInfo->m_bExpands) {
+			if ((padUsed->GetTarget() && weaponInfo->m_bCanAimWithArm) || padUsed->GetWeapon()) {
+				float limitedCam = CGeneral::LimitRadianAngle(-TheCamera.Orientation);
+
+				// On this one we can rotate arm.
+				if (weaponInfo->m_bCanAimWithArm) {
+					if (!padUsed->GetWeapon()) { // making this State != ATTACK still stops it after attack. Re-start it immediately!
+						SetPointGunAt(nil);
+						bIsPointingGunAt = false; // to not stop after attack
+					}
+
+					SetLookFlag(limitedCam, true);
+					SetAimFlag(limitedCam);
+#ifdef VC_PED_PORTS
+					SetLookTimer(INT_MAX); // removing this makes head move for real, but I experinced some bugs.
+#endif
+				} else {
+					m_fRotationDest = limitedCam;
+					m_headingRate = 50.0f;
+
+					// Anim. fix for shotgun, ak47 and m16 (we must finish rot. it quickly)
+					if (weaponInfo->m_bCanAim && padUsed->WeaponJustDown()) {
+						m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+						float limitedRotDest = m_fRotationDest;
+
+						if (m_fRotationCur - PI > m_fRotationDest) {
+							limitedRotDest += 2 * PI;
+						} else if (PI + m_fRotationCur < m_fRotationDest) {
+							limitedRotDest -= 2 * PI;
+						}
+
+						m_fRotationCur += (limitedRotDest - m_fRotationCur) / 2;
+					}
+				}
+			} else if (weaponInfo->m_bCanAimWithArm)
+				ClearPointGunAt();
+			else
+				RestoreHeadingRate();
+		}
+	}
+#endif
+
+	if (padUsed->GetTarget() && m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT) {
+		if (m_pPointGunAt) {
+			// what??
+			if (!m_pPointGunAt
+#ifdef FREE_CAM
+				|| (!CCamera::bFreeCam && CCamera::m_bUseMouse3rdPerson)
+#else
+				|| CCamera::m_bUseMouse3rdPerson
+#endif
+				|| m_pPointGunAt->IsPed() && ((CPed*)m_pPointGunAt)->bInVehicle) {
+				ClearWeaponTarget();
+				return;
+			}
+			if (CPlayerPed::DoesTargetHaveToBeBroken(m_pPointGunAt->GetPosition(), GetWeapon())) {
+				ClearWeaponTarget();
+				return;
+			}
+			if (m_pPointGunAt) {
+				if (padUsed->ShiftTargetLeftJustDown())
+					FindNextWeaponLockOnTarget(m_pPointGunAt, true);
+				if (padUsed->ShiftTargetRightJustDown())
+					FindNextWeaponLockOnTarget(m_pPointGunAt, false);
+			}
+			TheCamera.SetNewPlayerWeaponMode(CCam::MODE_SYPHON, 0, 0);
+			TheCamera.UpdateAimingCoors(m_pPointGunAt->GetPosition());
+		}
+#ifdef FREE_CAM
+		else if ((CCamera::bFreeCam && weaponInfo->m_eWeaponFire == WEAPON_FIRE_MELEE) || (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson)) {
+#else
+		else if (weaponInfo->m_bCanAim && !CCamera::m_bUseMouse3rdPerson) {
+#endif
+			if (padUsed->TargetJustDown())
+				FindWeaponLockOnTarget();
+		}
+	} else if (m_pPointGunAt) {
+		ClearWeaponTarget();
+	}
+
+	if (m_pPointGunAt) {
+#ifndef VC_PED_PORTS
+		CVector markPos = m_pPointGunAt->GetPosition();
+#else
+		CVector markPos;
+		if (m_pPointGunAt->IsPed()) {
+			((CPed*)m_pPointGunAt)->m_pedIK.GetComponentPosition((RwV3d*)markPos, PED_MID);
+		} else {
+			markPos = m_pPointGunAt->GetPosition();
+		}
+#endif
+		if (bCanPointGunAtTarget) {
+			CWeaponEffects::MarkTarget(markPos, 64, 0, 0, 255, 0.8f);
+		} else {
+			CWeaponEffects::MarkTarget(markPos, 64, 32, 0, 255, 0.8f);
+		}
+	}
+	m_bHasLockOnTarget = m_pPointGunAt != nil;
+}
+
+void
+CPlayerPed::PlayerControlZelda(CPad *padUsed)
+{
+	bool doSmoothSpray = DoWeaponSmoothSpray();
+	float camOrientation = TheCamera.Orientation;
+	float leftRight = padUsed->GetPedWalkLeftRight();
+	float upDown = padUsed->GetPedWalkUpDown();
+	float padMoveInGameUnit;
+	bool smoothSprayWithoutMove = false;
+
+	if (doSmoothSpray && upDown > 0.0f) {
+		padMoveInGameUnit = 0.0f;
+		smoothSprayWithoutMove = true;
+	} else {
+		padMoveInGameUnit = CVector2D(leftRight, upDown).Magnitude() / PAD_MOVE_TO_GAME_WORLD_MOVE;
+	}
+
+	if (padMoveInGameUnit > 0.0f || smoothSprayWithoutMove) {
+		float padHeading = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown);
+		float neededTurn = CGeneral::LimitRadianAngle(padHeading - camOrientation);
+		if (doSmoothSpray) {
+			if (GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER || GetWeapon()->m_eWeaponType == WEAPONTYPE_COLT45
+				|| GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI)
+				m_fRotationDest = m_fRotationCur - leftRight / 128.0f * (PI / 80.0f) * CTimer::GetTimeStep();
+			else
+				m_fRotationDest = m_fRotationCur - leftRight / 128.0f * (PI / 128.0f) * CTimer::GetTimeStep();
+		} else {
+			m_fRotationDest = neededTurn;
+		}
+
+		float maxAcc = 0.07f * CTimer::GetTimeStep();
+		m_fMoveSpeed = min(padMoveInGameUnit, m_fMoveSpeed + maxAcc);
+
+	} else {
+		m_fMoveSpeed = 0.0f;
+	}
+
+	if (m_nPedState == PED_JUMP) {
+		if (bIsInTheAir) {
+			if (bUsesCollision && !bHitSteepSlope &&
+				(!bHitSomethingLastFrame || m_vecDamageNormal.z > 0.6f)
+				&& m_fDistanceTravelled < CTimer::GetTimeStep() * 0.02 && m_vecMoveSpeed.MagnitudeSqr() < 0.01f) {
+
+				float angleSin = Sin(m_fRotationCur); // originally sin(DEGTORAD(RADTODEG(m_fRotationCur))) o_O
+				float angleCos = Cos(m_fRotationCur);
+				ApplyMoveForce(-angleSin * 3.0f, 3.0f * angleCos, 0.05f);
+			}
+		} else if (bIsLanding) {
+			m_fMoveSpeed = 0.0f;
+		}
+	}
+
+	if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
+		&& padUsed->GetSprint()) {
+		m_nMoveState = PEDMOVE_SPRINT;
+	}
+	if (m_nPedState != PED_FIGHT)
+		SetRealMoveAnim();
+
+	if (!bIsInTheAir && !(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy)
+		&& padUsed->JumpJustDown() && m_nPedState != PED_JUMP) {
+		ClearAttack();
+		ClearWeaponTarget();
+		if (m_nEvadeAmount != 0 && m_pEvadingFrom) {
+			SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1);
+			m_nEvadeAmount = 0;
+			m_pEvadingFrom = nil;
+		} else {
+			SetJump();
+		}
+	}
+}
+
+void
+CPlayerPed::ProcessControl(void)
+{
+	if (m_nEvadeAmount != 0)
+		--m_nEvadeAmount;
+
+	if (m_nEvadeAmount == 0)
+		m_pEvadingFrom = nil;
+
+	if (m_pCurrentPhysSurface && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) {
+		bTryingToReachDryLand = true;
+	} else if (!(((uint8)CTimer::GetFrameCounter() + m_randomSeed) & 0xF)) {
+		CVehicle *nearVeh = (CVehicle*)CWorld::TestSphereAgainstWorld(GetPosition(), 7.0f, nil,
+								false, true, false, false, false, false);
+		if (nearVeh && nearVeh->IsBoat())
+			bTryingToReachDryLand = true;
+		else
+			bTryingToReachDryLand = false;
+	}
+	CPed::ProcessControl();
+	if (bWasPostponed)
+		return;
+
+	CPad *padUsed = CPad::GetPad(0);
+	m_pWanted->Update();
+	CEntity::PruneReferences();
+
+	if (m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT)
+		RestoreSprintEnergy(1.0f);
+	else if (m_nMoveState == PEDMOVE_RUN)
+		RestoreSprintEnergy(0.3f);
+
+	if (m_nPedState == PED_DEAD) {
+		ClearWeaponTarget();
+		return;
+	}
+	if (m_nPedState == PED_DIE) {
+		ClearWeaponTarget();
+		if (CTimer::GetTimeInMilliseconds() > m_bloodyFootprintCountOrDeathTime + 4000)
+			SetDead();
+		return;
+	}
+	if (m_nPedState == PED_DRIVING && m_objective != OBJECTIVE_LEAVE_VEHICLE) {
+		if (m_pMyVehicle->IsCar() && ((CAutomobile*)m_pMyVehicle)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) == DOOR_STATUS_SWINGING) {
+			CAnimBlendAssociation *rollDoorAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_ROLLDOOR);
+			if (!rollDoorAssoc) {
+				rollDoorAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_ROLLDOOR_LOW);
+			}
+
+			// These comparisons are wrong, they return uint16
+			if (m_pMyVehicle->m_nGettingOutFlags & CAR_DOOR_FLAG_LF || rollDoorAssoc || padUsed
+				&& (padUsed->GetAccelerate() != 0.0f || padUsed->GetSteeringLeftRight() != 0.0f
+					|| padUsed->GetBrake() != 0.0f)) {
+
+				if (rollDoorAssoc)
+					m_pMyVehicle->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR, rollDoorAssoc->currentTime);
+			} else {
+				m_pMyVehicle->m_nGettingOutFlags |= CAR_DOOR_FLAG_LF;
+				if (m_pMyVehicle->bLowVehicle)
+					rollDoorAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ROLLDOOR_LOW);
+				else
+					rollDoorAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ROLLDOOR);
+
+				rollDoorAssoc->SetFinishCallback(PedAnimDoorCloseRollingCB, this);
+			}
+		}
+		return;
+	}
+	if (m_objective == OBJECTIVE_NONE)
+		m_nMoveState = PEDMOVE_STILL;
+	if (bIsLanding)
+		RunningLand(padUsed);
+	if (padUsed && padUsed->WeaponJustDown() && m_nPedState != PED_SNIPER_MODE) {
+
+		// ...Really?
+		eWeaponType playerWeapon = FindPlayerPed()->GetWeapon()->m_eWeaponType;
+		if (playerWeapon == WEAPONTYPE_SNIPERRIFLE) {
+			DMAudio.PlayFrontEndSound(SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM, 0);
+		} else if (playerWeapon == WEAPONTYPE_ROCKETLAUNCHER) {
+			DMAudio.PlayFrontEndSound(SOUND_WEAPON_ROCKET_SHOT_NO_ZOOM, 0);
+		}
+	}
+
+	switch (m_nPedState) {
+		case PED_NONE:
+		case PED_IDLE:
+		case PED_FLEE_POS:
+		case PED_FLEE_ENTITY:
+		case PED_ATTACK:
+		case PED_FIGHT:
+		case PED_AIM_GUN:
+			if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG400)) {
+				if (TheCamera.Cams[0].Using3rdPersonMouseCam()) {
+					if (padUsed)
+						PlayerControl1stPersonRunAround(padUsed);
+				} else if (m_nPedState == PED_FIGHT) {
+					if (padUsed)
+						PlayerControlFighter(padUsed);
+				} else if (padUsed) {
+					PlayerControlZelda(padUsed);
+				}
+			}
+			if (IsPedInControl() && padUsed)
+				ProcessPlayerWeapon(padUsed);
+			break;
+		case PED_LOOK_ENTITY:
+		case PED_LOOK_HEADING:
+		case PED_WANDER_RANGE:
+		case PED_WANDER_PATH:
+		case PED_PURSUE:
+		case PED_FOLLOW_PATH:
+		case PED_ROCKET_ODE:
+		case PED_DUMMY:
+		case PED_PAUSE:
+		case PED_FACE_PHONE:
+		case PED_MAKE_CALL:
+		case PED_CHAT:
+		case PED_MUG:
+		case PED_AI_CONTROL:
+		case PED_FOLLOW_ROUTE:
+		case PED_CPR:
+		case PED_SOLICIT:
+		case PED_BUY_ICECREAM:
+		case PED_INVESTIGATE:
+		case PED_STEP_AWAY:
+		case PED_ON_FIRE:
+		case PED_UNKNOWN:
+		case PED_STATES_NO_AI:
+		case PED_STAGGER:
+		case PED_DIVE_AWAY:
+		case PED_STATES_NO_ST:
+		case PED_ARREST_PLAYER:
+		case PED_DRIVING:
+		case PED_PASSENGER:
+		case PED_TAXI_PASSENGER:
+		case PED_OPEN_DOOR:
+		case PED_DIE:
+		case PED_DEAD:
+		case PED_HANDS_UP:
+			break;
+		case PED_SEEK_ENTITY:
+			m_vecSeekPos = m_pSeekTarget->GetPosition();
+
+			// fall through
+		case PED_SEEK_POS:
+			switch (m_nMoveState) {
+				case PEDMOVE_WALK:
+					m_fMoveSpeed = 1.0f;
+					break;
+				case PEDMOVE_RUN:
+					m_fMoveSpeed = 1.8f;
+					break;
+				case PEDMOVE_SPRINT:
+					m_fMoveSpeed = 2.5f;
+					break;
+				default:
+					m_fMoveSpeed = 0.0f;
+					break;
+			}
+			SetRealMoveAnim();
+			if (Seek()) {
+				RestorePreviousState();
+				SetMoveState(PEDMOVE_STILL);
+			}
+			break;
+		case PED_SNIPER_MODE:
+			if (FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_M16) {
+				if (padUsed)
+					PlayerControlM16(padUsed);
+			} else if (padUsed) {
+				PlayerControlSniper(padUsed);
+			}
+			break;
+		case PED_SEEK_CAR:
+		case PED_SEEK_IN_BOAT:
+			if (bVehEnterDoorIsBlocked || bKindaStayInSamePlace) {
+				m_fMoveSpeed = 0.0f;
+			} else {
+				m_fMoveSpeed = min(2.0f, 2.0f * (m_vecSeekPos - GetPosition()).Magnitude2D());
+			}
+			if (padUsed && !padUsed->ArePlayerControlsDisabled()) {
+				if (padUsed->GetTarget() || padUsed->GetLeftStickXJustDown() || padUsed->GetLeftStickYJustDown() ||
+					padUsed->GetDPadUpJustDown() || padUsed->GetDPadDownJustDown() || padUsed->GetDPadLeftJustDown() ||
+					padUsed->GetDPadRightJustDown()) {
+
+					RestorePreviousState();
+					if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) {
+						RestorePreviousObjective();
+					}
+				}
+			}
+			if (padUsed && padUsed->GetSprint())
+				m_nMoveState = PEDMOVE_SPRINT;
+			SetRealMoveAnim();
+			break;
+		case PED_JUMP:
+			if (padUsed)
+				PlayerControlZelda(padUsed);
+			if (bIsLanding)
+				break;
+
+			// This has been added later it seems
+			return;
+		case PED_FALL:
+		case PED_GETUP:
+		case PED_ENTER_TRAIN:
+		case PED_EXIT_TRAIN:
+		case PED_CARJACK:
+		case PED_DRAG_FROM_CAR:
+		case PED_ENTER_CAR:
+		case PED_STEAL_CAR:
+		case PED_EXIT_CAR:
+			ClearWeaponTarget();
+			break;
+		case PED_ARRESTED:
+			if (m_nLastPedState == PED_DRAG_FROM_CAR && m_pVehicleAnim)
+				BeingDraggedFromCar();
+			break;
+	}
+	if (padUsed && IsPedShootable()) {
+		ProcessWeaponSwitch(padUsed);
+		GetWeapon()->Update(m_audioEntityId);
+	}
+	ProcessAnimGroups();
+	if (padUsed) {
+		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FOLLOWPED
+			&& TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_BEHIND) {
+
+			m_lookTimer = 0;
+			float camAngle = CGeneral::LimitRadianAngle(TheCamera.Cams[TheCamera.ActiveCam].Front.Heading());
+			float angleBetweenPlayerAndCam = Abs(camAngle - m_fRotationCur);
+			if (m_nPedState != PED_ATTACK
+				&& angleBetweenPlayerAndCam > DEGTORAD(30.0f) && angleBetweenPlayerAndCam < DEGTORAD(330.0f)) {
+
+				if (angleBetweenPlayerAndCam > DEGTORAD(150.0f) && angleBetweenPlayerAndCam < DEGTORAD(210.0f)) {
+					float rightTurnAngle = CGeneral::LimitRadianAngle(m_fRotationCur - DEGTORAD(150.0f));
+					float leftTurnAngle = CGeneral::LimitRadianAngle(DEGTORAD(150.0f) + m_fRotationCur);
+					if (m_fLookDirection != 999999.0f) {
+						if (Abs(rightTurnAngle - m_fLookDirection) < Abs(leftTurnAngle - m_fLookDirection))
+							camAngle = rightTurnAngle;
+						else
+							camAngle = leftTurnAngle;
+					} else {
+						camAngle = rightTurnAngle;
+					}
+				}
+				SetLookFlag(camAngle, true);
+				SetLookTimer(CTimer::GetTimeStepInMilliseconds() * 5.0f);
+			} else {
+				ClearLookFlag();
+			}
+		}
+	}
+	if (m_nMoveState == PEDMOVE_SPRINT && bIsLooking) {
+		ClearLookFlag();
+		SetLookTimer(250);
+	}
+
+	if (m_vecMoveSpeed.Magnitude2D() < 0.1f) {
+		if (m_nSpeedTimer) {
+			if (CTimer::GetTimeInMilliseconds() > m_nSpeedTimer)
+				m_bSpeedTimerFlag = true;
+		} else {
+			m_nSpeedTimer = CTimer::GetTimeInMilliseconds() + 500;
+		}
+	} else {
+		m_nSpeedTimer = 0;
+		m_bSpeedTimerFlag = false;
+	}
+}
+
+#include <new>
+
+class CPlayerPed_ : public CPlayerPed
+{
+public:
+	CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); }
+	void dtor(void) { CPlayerPed::~CPlayerPed(); }
+	void SetMoveAnim_(void) { CPlayerPed::SetMoveAnim(); }
+	void ProcessControl_(void) { CPlayerPed::ProcessControl(); }
+};
+
+STARTPATCHES
+	InjectHook(0x4EF7E0, &CPlayerPed_::ctor, PATCH_JUMP);
+	InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP);
+	InjectHook(0x4F3760, &CPlayerPed_::SetMoveAnim_, PATCH_JUMP);
+	InjectHook(0x4EFD90, &CPlayerPed_::ProcessControl_, PATCH_JUMP);
+	InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP);
+	InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP);
+	InjectHook(0x4F36C0, &CPlayerPed::GetPlayerInfoForThisPlayerPed, PATCH_JUMP);
+	InjectHook(0x4F2560, &CPlayerPed::MakeChangesForNewWeapon, PATCH_JUMP);
+	InjectHook(0x4F07C0, &CPlayerPed::ReApplyMoveAnims, PATCH_JUMP);
+	InjectHook(0x4F0880, &CPlayerPed::SetRealMoveAnim, PATCH_JUMP);
+	InjectHook(0x4F1810, &CPlayerPed::PlayerControlFighter, PATCH_JUMP);
+	InjectHook(0x4F1340, &CPlayerPed::RestoreSprintEnergy, PATCH_JUMP);
+	InjectHook(0x4F1380, &CPlayerPed::DoWeaponSmoothSpray, PATCH_JUMP);
+	InjectHook(0x4F36E0, &CPlayerPed::DoStuffToGoOnFire, PATCH_JUMP);
+	InjectHook(0x4F3350, &CPlayerPed::DoesTargetHaveToBeBroken, PATCH_JUMP);
+	InjectHook(0x4F31D0, &CPlayerPed::RunningLand, PATCH_JUMP);
+	InjectHook(0x4F2D00, &CPlayerPed::IsThisPedAttackingPlayer, PATCH_JUMP);
+	InjectHook(0x4F1CF0, &CPlayerPed::PlayerControlSniper, PATCH_JUMP);
+	InjectHook(0x4F2310, &CPlayerPed::ProcessWeaponSwitch, PATCH_JUMP);
+	InjectHook(0x4F1DF0, &CPlayerPed::PlayerControlM16, PATCH_JUMP);
+	InjectHook(0x4F3460, &CPlayerPed::KeepAreaAroundPlayerClear, PATCH_JUMP);
+	InjectHook(0x4F1970, &CPlayerPed::PlayerControl1stPersonRunAround, PATCH_JUMP);
+	InjectHook(0x4F1EF0, &CPlayerPed::ProcessPlayerWeapon, PATCH_JUMP);
+	InjectHook(0x4F2640, &CPlayerPed::ProcessAnimGroups, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp
index 3bf81066..6959487f 100644
--- a/src/peds/Population.cpp
+++ b/src/peds/Population.cpp
@@ -29,39 +29,54 @@
 #define PED_REMOVE_DIST			(MIN_CREATION_DIST + CREATION_RANGE + 1.0f)
 #define PED_REMOVE_DIST_SPECIAL	(MIN_CREATION_DIST + CREATION_RANGE + 15.0f) // for peds with bCullExtraFarAway flag
 
-// TO-DO: These are hard-coded, reverse them.
-// More clearly they're transition areas between zones.
-RegenerationPoint (&aSafeZones)[8] = *(RegenerationPoint(*)[8]) * (uintptr*)0x5FA578;
+// Transition areas between zones
+const RegenerationPoint aSafeZones[] = {
+	{ LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 400.0f, 814.0f, -954.0f, -903.0f, 30.0f, 100.0f,
+		CVector(790.0f, -917.0f, 39.0f), CVector(775.0f, -921.0f, 39.0f), CVector(424.0f, -942.0f, 38.0f), CVector(439.0f, -938.0f, 38.0f) },
+	{ LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 555.0f, 711.0f, 118.0f, 186.0f, -30.0f, -10.0f,
+		CVector(698.0f,  182.0f, -20.0f), CVector(681.0f,  178.0f, -20.0f), CVector(586.0f,  144.0f, -20.0f), CVector(577.0f,  135.0f, -20.0f) },
+	{ LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 26.0f, 44.0f, 124.0f, 87.0f, 20.0f, 6.0f,
+		CVector(736.0f, -117.0f, -13.0f), CVector(730.0f, -115.0f, -13.0f), CVector(635.0f, -93.0f, -12.5f), CVector(650.0f, -89.0f, -12.5f) },
+	{ LEVEL_INDUSTRIAL, LEVEL_COMMERCIAL, 45.0f, 34.0f, 780.0f, 750.0f, 25.0f, 6.0f,
+		CVector(729.0f, -764.0f, -18.0f), CVector(720.0f, -769.0f, -17.0f), CVector(652.0f, -774.0f, -10.5f), CVector(659.0f, -770.0f, -10.5f) },
+	{ LEVEL_COMMERCIAL, LEVEL_SUBURBAN, 532.0f, 136.0f, 668.0f, 599.0f, 4.0f, 0.0f,
+		CVector(-172.0f, -619.0f,  44.0f), CVector(-183.0f, -623.0f,  44.0f), CVector(-511.0f, -645.0f,  41.0f), CVector(-493.0f, -639.0f,  41.5f) },
+	{ LEVEL_COMMERCIAL, LEVEL_SUBURBAN, 325.0f, 175.0f, 7.0f, 5.0f, 30.0f, 10.0f,
+		CVector(-185.0f,  40.8f, -20.5f), CVector(-202.0f,  37.0f, -20.5f), CVector(-315.0f,  65.5f, -20.5f), CVector(-306.0f,  62.4f, -20.5f) },
+	{ LEVEL_COMMERCIAL, LEVEL_SUBURBAN, 410.0f, 310.0f, 1055.0f, 1030.0f, 20.0f, 6.0f,
+		CVector(-321.0f, -1043.0f, -13.2f), CVector(-328.0f, -1045.0f, -13.2f), CVector(-398.0f, -1044.0f, -13.5f), CVector(-390.0f, -1040.5f, -13.5f) },
+	{ LEVEL_COMMERCIAL, LEVEL_SUBURBAN, 425.0f, 280.0f, 471.0f, 447.0f, 20.0f, 5.0f,
+		CVector(-292.0f, -457.0f, -11.6f), CVector(-310.0f, -461.0f, -11.6f), CVector(-413.0f, -461.0f, -11.5f), CVector(-399.0f, -457.0f, -11.3f) }
+}; // *(RegenerationPoint(*)[8]) * (uintptr*)0x5FA578;
 
-//PedGroup (&CPopulation::ms_pPedGroups)[NUMPEDGROUPS] = *(PedGroup(*)[NUMPEDGROUPS]) * (uintptr*)0x6E9248;
-PedGroup CPopulation::ms_pPedGroups[NUMPEDGROUPS];
-bool &CPopulation::ms_bGivePedsWeapons = *(bool*)0x95CCF6;
-int32 &CPopulation::m_AllRandomPedsThisType = *(int32*)0x5FA570;
-float &CPopulation::PedDensityMultiplier = *(float*)0x5FA56C;
-uint32 &CPopulation::ms_nTotalMissionPeds = *(uint32*)0x8F5F70;
-int32 &CPopulation::MaxNumberOfPedsInUse = *(int32*)0x5FA574;
-uint32& CPopulation::ms_nNumCivMale = *(uint32*)0x8F2548;
-uint32& CPopulation::ms_nNumCivFemale = *(uint32*)0x8F5F44;
-uint32& CPopulation::ms_nNumCop = *(uint32*)0x885AFC;
-bool& CPopulation::bZoneChangeHasHappened = *(bool*)0x95CD79;
-uint32& CPopulation::ms_nNumEmergency = *(uint32*)0x94071C;
-int8& CPopulation::m_CountDownToPedsAtStart = *(int8*)0x95CD4F;
-uint32& CPopulation::ms_nNumGang1 = *(uint32*)0x8F1B1C;
-uint32& CPopulation::ms_nNumGang2 = *(uint32*)0x8F1B14;
-uint32& CPopulation::ms_nTotalPeds = *(uint32*)0x95CB50;
-uint32& CPopulation::ms_nNumGang3 = *(uint32*)0x8F2548;
-uint32& CPopulation::ms_nTotalGangPeds = *(uint32*)0x885AF0;
-uint32& CPopulation::ms_nNumGang4 = *(uint32*)0x8F1B2C;
-uint32& CPopulation::ms_nTotalCivPeds = *(uint32*)0x8F2C3C;
-uint32& CPopulation::ms_nNumGang5 = *(uint32*)0x8F1B30;
-uint32& CPopulation::ms_nNumDummy = *(uint32*)0x8F1A98;
-uint32& CPopulation::ms_nNumGang6 = *(uint32*)0x8F1B20;
-uint32& CPopulation::ms_nNumGang9 = *(uint32*)0x8F1B10;
-uint32& CPopulation::ms_nNumGang7 = *(uint32*)0x8F1B28;
-uint32& CPopulation::ms_nNumGang8 = *(uint32*)0x8F1B0C;
-CVector &CPopulation::RegenerationPoint_a = *(CVector*)0x8E2AA4;
-CVector &CPopulation::RegenerationPoint_b = *(CVector*)0x8E2A98;
-CVector &CPopulation::RegenerationForward = *(CVector*)0x8F1AD4;
+PedGroup CPopulation::ms_pPedGroups[NUMPEDGROUPS]; // = *(PedGroup(*)[NUMPEDGROUPS]) * (uintptr*)0x6E9248;
+bool CPopulation::ms_bGivePedsWeapons; // = *(bool*)0x95CCF6;
+int32 CPopulation::m_AllRandomPedsThisType = -1; // = *(int32*)0x5FA570;
+float CPopulation::PedDensityMultiplier = 1.0f; // = *(float*)0x5FA56C;
+uint32 CPopulation::ms_nTotalMissionPeds; // = *(uint32*)0x8F5F70;
+int32 CPopulation::MaxNumberOfPedsInUse = 25; // *(int32*)0x5FA574;
+uint32 CPopulation::ms_nNumCivMale; // = *(uint32*)0x8F2548;
+uint32 CPopulation::ms_nNumCivFemale; // = *(uint32*)0x8F5F44;
+uint32 CPopulation::ms_nNumCop; // = *(uint32*)0x885AFC;
+bool CPopulation::bZoneChangeHasHappened; // = *(bool*)0x95CD79;
+uint32 CPopulation::ms_nNumEmergency; // = *(uint32*)0x94071C;
+int8 CPopulation::m_CountDownToPedsAtStart; // = *(int8*)0x95CD4F;
+uint32 CPopulation::ms_nNumGang1; // = *(uint32*)0x8F1B1C;
+uint32 CPopulation::ms_nNumGang2; // = *(uint32*)0x8F1B14;
+uint32 CPopulation::ms_nTotalPeds; // = *(uint32*)0x95CB50;
+uint32 CPopulation::ms_nNumGang3; // = *(uint32*)0x8F2548;
+uint32 CPopulation::ms_nTotalGangPeds; // = *(uint32*)0x885AF0;
+uint32 CPopulation::ms_nNumGang4; // = *(uint32*)0x8F1B2C;
+uint32 CPopulation::ms_nTotalCivPeds; // = *(uint32*)0x8F2C3C;
+uint32 CPopulation::ms_nNumGang5; // = *(uint32*)0x8F1B30;
+uint32 CPopulation::ms_nNumDummy; // = *(uint32*)0x8F1A98;
+uint32 CPopulation::ms_nNumGang6; // = *(uint32*)0x8F1B20;
+uint32 CPopulation::ms_nNumGang9; // = *(uint32*)0x8F1B10;
+uint32 CPopulation::ms_nNumGang7; // = *(uint32*)0x8F1B28;
+uint32 CPopulation::ms_nNumGang8; // = *(uint32*)0x8F1B0C;
+CVector CPopulation::RegenerationPoint_a; // = *(CVector*)0x8E2AA4;
+CVector CPopulation::RegenerationPoint_b; // = *(CVector*)0x8E2A98;
+CVector CPopulation::RegenerationForward; // = *(CVector*)0x8F1AD4;
 
 void
 CPopulation::Initialise()
@@ -704,12 +719,15 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree
 			if (i != 0) {
 				// Gang member
 				newPed->SetLeader(gangLeader);
+#ifndef FIX_BUGS
+				// seems to be a miami leftover (this code is not on PS2) but gang peds end up just being frozen
 				newPed->m_nPedState = PED_UNKNOWN;
 				gangLeader->m_nPedState = PED_UNKNOWN;
 				newPed->m_fRotationCur = CGeneral::GetRadianAngleBetweenPoints(
 					gangLeader->GetPosition().x, gangLeader->GetPosition().y,
 					newPed->GetPosition().x, newPed->GetPosition().y);
 				newPed->m_fRotationDest = newPed->m_fRotationCur;
+#endif
 			} else {
 				gangLeader = newPed;
 			}
@@ -964,7 +982,7 @@ CPopulation::ConvertToRealObject(CDummyObject *dummy)
 	} else if (obj->m_modelIndex == MI_BUOY) {
 		obj->bIsStatic = false;
 		obj->m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.001f);
-		obj->m_flagD8 = true;
+		obj->bTouchingWater = true;
 		obj->AddToMovingList();
 	}
 }
diff --git a/src/peds/Population.h b/src/peds/Population.h
index f9e6c3b7..aa8129c0 100644
--- a/src/peds/Population.h
+++ b/src/peds/Population.h
@@ -34,33 +34,33 @@ class CPopulation
 {
 public:
 	static PedGroup ms_pPedGroups[NUMPEDGROUPS];
-	static bool &ms_bGivePedsWeapons;
-	static int32 &m_AllRandomPedsThisType;
-	static float &PedDensityMultiplier;
-	static uint32 &ms_nTotalMissionPeds;
-	static int32 &MaxNumberOfPedsInUse;
-	static uint32& ms_nNumCivMale;
-	static uint32 &ms_nNumCivFemale;
-	static uint32 &ms_nNumCop;
-	static bool &bZoneChangeHasHappened;
-	static uint32 &ms_nNumEmergency;
-	static int8& m_CountDownToPedsAtStart;
-	static uint32& ms_nNumGang1;
-	static uint32& ms_nNumGang2;
-	static uint32& ms_nTotalPeds;
-	static uint32& ms_nNumGang3;
-	static uint32& ms_nTotalGangPeds;
-	static uint32& ms_nNumGang4;
-	static uint32& ms_nTotalCivPeds;
-	static uint32& ms_nNumGang5;
-	static uint32& ms_nNumDummy;
-	static uint32& ms_nNumGang6;
-	static uint32& ms_nNumGang9;
-	static uint32& ms_nNumGang7;
-	static uint32& ms_nNumGang8;
-	static CVector& RegenerationPoint_a;
-	static CVector& RegenerationPoint_b;
-	static CVector& RegenerationForward;
+	static bool ms_bGivePedsWeapons;
+	static int32 m_AllRandomPedsThisType;
+	static float PedDensityMultiplier;
+	static uint32 ms_nTotalMissionPeds;
+	static int32 MaxNumberOfPedsInUse;
+	static uint32 ms_nNumCivMale;
+	static uint32 ms_nNumCivFemale;
+	static uint32 ms_nNumCop;
+	static bool bZoneChangeHasHappened;
+	static uint32 ms_nNumEmergency;
+	static int8 m_CountDownToPedsAtStart;
+	static uint32 ms_nNumGang1;
+	static uint32 ms_nNumGang2;
+	static uint32 ms_nTotalPeds;
+	static uint32 ms_nNumGang3;
+	static uint32 ms_nTotalGangPeds;
+	static uint32 ms_nNumGang4;
+	static uint32 ms_nTotalCivPeds;
+	static uint32 ms_nNumGang5;
+	static uint32 ms_nNumDummy;
+	static uint32 ms_nNumGang6;
+	static uint32 ms_nNumGang9;
+	static uint32 ms_nNumGang7;
+	static uint32 ms_nNumGang8;
+	static CVector RegenerationPoint_a;
+	static CVector RegenerationPoint_b;
+	static CVector RegenerationForward;
 
 	static void Initialise();
 	static void Update(void);
diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp
index 2884894c..39866294 100644
--- a/src/render/Clouds.cpp
+++ b/src/render/Clouds.cpp
@@ -87,7 +87,7 @@ CClouds::Render(void)
 		RwV3d pos = { 0.0f, -100.0f, 15.0f };
 		RwV3dAdd(&worldpos, &campos, &pos);
 		if(CSprite::CalcScreenCoors(worldpos, &screenpos, &szx, &szy, false)){
-			RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[2]->raster);
+			RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[2]));
 			if(CCoronas::bSmallMoon){
 				szx *= 4.0f;
 				szy *= 4.0f;
@@ -116,7 +116,7 @@ CClouds::Render(void)
 		static float StarCoorsY[9] = { 0.0f, 0.45f, 0.9f, 1.0f, 0.85f, 0.52f, 0.48f, 0.35f, 0.2f };
 		static float StarSizes[9] = { 1.0f, 1.4f, 0.9f, 1.0f, 0.6f, 1.5f, 1.3f, 1.0f, 0.8f };
 		int brightness = (1.0f - coverage) * starintens;
-		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
 		for(i = 0; i < 11; i++){
 			RwV3d pos = { 100.0f, 0.0f, 10.0f };
 			if(i >= 9) pos.x = -pos.x;
@@ -132,7 +132,7 @@ CClouds::Render(void)
 		CSprite::FlushSpriteBuffer();
 
 		// *
-		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
 		RwV3d pos = { 100.0f, 0.0f, 10.0f };
 		RwV3dAdd(&worldpos, &campos, &pos);
 		worldpos.y -= 90.0f;
@@ -156,7 +156,7 @@ CClouds::Render(void)
 	int b = CTimeCycle::GetLowCloudsBlue() * lowcloudintensity;
 	for(int cloudtype = 0; cloudtype < 3; cloudtype++){
 		for(i = cloudtype; i < 12; i += 3){
-			RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[cloudtype]->raster);
+			RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[cloudtype]));
 			RwV3d pos = { 800.0f*LowCloudsX[i], 800.0f*LowCloudsY[i], 60.0f*LowCloudsZ[i] };
 			worldpos.x = campos.x + pos.x;
 			worldpos.y = campos.y + pos.y;
@@ -202,7 +202,7 @@ CClouds::Render(void)
 
 		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
 		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[4]->raster);
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[4]));
 		for(i = 0; i < 37; i++){
 			RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
 			worldpos.x = pos.x*rot_cos + pos.y*rot_sin + campos.x;
@@ -244,7 +244,7 @@ CClouds::Render(void)
 		// Highlights
 		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
 		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
-		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCloudTex[3]->raster);
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCloudTex[3]));
 
 		for(i = 0; i < 37; i++){
 			RwV3d pos = { 2.0f*CoorsOffsetX[i], 2.0f*CoorsOffsetY[i], 40.0f*CoorsOffsetZ[i] + 40.0f };
@@ -269,7 +269,7 @@ CClouds::Render(void)
 		static uint8 BowRed[6] = { 30, 30, 30, 10, 0, 15 };
 		static uint8 BowGreen[6] = { 0, 15, 30, 30, 0, 0 };
 		static uint8 BowBlue[6] = { 0, 0, 0, 10, 30, 30 };
-		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpCoronaTexture[0]->raster);
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[0]));
 		for(i = 0; i < 6; i++){
 			RwV3d pos = { i*1.5f, 100.0f, 5.0f };
 			RwV3dAdd(&worldpos, &campos, &pos);
diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp
index c934540b..68994b0b 100644
--- a/src/render/Coronas.cpp
+++ b/src/render/Coronas.cpp
@@ -320,7 +320,7 @@ CCoronas::Render(void)
 
 						CSprite::RenderOneXLUSprite(spriteCoors.x, spriteCoors.y, spriteCoors.z,
 							spritew * aCoronas[i].size * wscale,
-							spriteh * SCREEN_SCALE_AR2(aCoronas[i].size * fogscale * hscale),
+							spriteh * aCoronas[i].size * fogscale * hscale,
 							CCoronas::aCoronas[i].red / fogscale,
 							CCoronas::aCoronas[i].green / fogscale,
 							CCoronas::aCoronas[i].blue / fogscale,
@@ -331,7 +331,7 @@ CCoronas::Render(void)
 						CSprite::RenderOneXLUSprite_Rotate_Aspect(
 							spriteCoors.x, spriteCoors.y, spriteCoors.z,
 							spritew * aCoronas[i].size * fogscale,
-							spriteh * SCREEN_SCALE_AR2(aCoronas[i].size * fogscale),
+							spriteh * aCoronas[i].size * fogscale,
 							CCoronas::aCoronas[i].red / fogscale,
 							CCoronas::aCoronas[i].green / fogscale,
 							CCoronas::aCoronas[i].blue / fogscale,
diff --git a/src/render/Fluff.cpp b/src/render/Fluff.cpp
index 8d7fad92..e2899532 100644
--- a/src/render/Fluff.cpp
+++ b/src/render/Fluff.cpp
@@ -755,14 +755,14 @@ void CTowerClock::Render()
 			&TempV[1],
 			m_Position.x + Sin(angleMinute) * m_fScale * m_Size.x,
 			m_Position.y + Sin(angleMinute) * m_fScale * m_Size.y,
-			m_Position.z + Cos(angleMinute) * m_fScale;
+			m_Position.z + Cos(angleMinute) * m_fScale
 		);
 		RwIm3DVertexSetPos(&TempV[2], m_Position.x, m_Position.y, m_Position.z);
 		RwIm3DVertexSetPos(
 			&TempV[3],
 			m_Position.x + Sin(angleHour) * 0.75f * m_fScale * m_Size.x,
 			m_Position.y + Sin(angleHour) * 0.75f * m_fScale * m_Size.y,
-			m_Position.z + Cos(angleHour) * 0.75f * m_fScale;
+			m_Position.z + Cos(angleHour) * 0.75f * m_fScale
 		);
 
 		LittleTest();
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index 3c07039c..56a024a7 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -23,55 +23,47 @@
 
 //wchar *CHud::m_HelpMessage = (wchar*)0x86B888;
 //wchar *CHud::m_LastHelpMessage = (wchar*)0x6E8F28;
-wchar CHud::m_HelpMessage[256];
-wchar CHud::m_LastHelpMessage[256];
-
-int32 &CHud::m_HelpMessageState = *(int32*)0x880E1C;
-int32 &CHud::m_HelpMessageTimer = *(int32*)0x880FA4;
-int32 &CHud::m_HelpMessageFadeTimer = *(int32*)0x8F6258;
-wchar *CHud::m_HelpMessageToPrint = (wchar*)0x664480;
-float &CHud::m_HelpMessageDisplayTime = *(float*)0x8E2C28;
-float &CHud::m_fTextBoxNumLines = *(float*)0x8E2C28;
-float &CHud::m_fHelpMessageTime = *(float *)0x8E2C28;
-bool &CHud::m_HelpMessageQuick = *(bool *)0x95CCF7;
-int32 CHud::m_ZoneState = *(int32*)0x8F29AC;
+wchar CHud::m_HelpMessageToPrint[256]; // = (wchar*)0x664480;
+float CHud::m_fHelpMessageTime; // *(float *)0x8E2C28;
+bool CHud::m_HelpMessageQuick; // = *(bool*)0x95CCF7;
+uint32 CHud::m_ZoneState; // = *(int32*)0x8F29AC;
 int32 CHud::m_ZoneFadeTimer;
-int32 CHud::m_ZoneNameTimer = *(int32*)0x8F1A50;
-wchar *&CHud::m_pZoneName = *(wchar **)0x8E2C2C;
-wchar *CHud::m_pLastZoneName = (wchar*)0x8F432C;
+uint32 CHud::m_ZoneNameTimer; // = *(int32*)0x8F1A50;
+wchar *CHud::m_pZoneName; // = *(wchar**)0x8E2C2C;
+wchar *CHud::m_pLastZoneName; // = (wchar*)0x8F432C;
 wchar *CHud::m_ZoneToPrint;
-int32 CHud::m_VehicleState = *(int32*)0x940560;
+uint32 CHud::m_VehicleState; // = *(int32*)0x940560;
 int32 CHud::m_VehicleFadeTimer;
-int32 CHud::m_VehicleNameTimer = *(int32*)0x8F2A14;
-wchar *&CHud::m_VehicleName = *(wchar **)0x942FB4;
-wchar *CHud::m_pLastVehicleName = *(wchar **)0x8E2DD8;
+uint32 CHud::m_VehicleNameTimer; // = *(int32*)0x8F2A14;
+wchar *CHud::m_VehicleName; // = *(wchar**)0x942FB4;
+wchar *CHud::m_pLastVehicleName; // = *(wchar**)0x8E2DD8;
 wchar *CHud::m_pVehicleNameToPrint;
-wchar *CHud::m_Message = (wchar*)0x72E318;
-wchar *CHud::m_PagerMessage = (wchar*)0x878840;
-bool &CHud::m_Wants_To_Draw_Hud = *(bool*)0x95CD89;
-bool &CHud::m_Wants_To_Draw_3dMarkers = *(bool*)0x95CD62;
-wchar(&CHud::m_BigMessage)[6][128] = *(wchar(*)[6][128])*(uintptr*)0x664CE0;
-int16 &CHud::m_ItemToFlash = *(int16*)0x95CC82;
+wchar CHud::m_Message[256];// = (wchar*)0x72E318;
+wchar CHud::m_PagerMessage[256]; // = (wchar*)0x878840;
+bool CHud::m_Wants_To_Draw_Hud; // (bool*)0x95CD89;
+bool CHud::m_Wants_To_Draw_3dMarkers; // = *(bool*)0x95CD62;
+wchar CHud::m_BigMessage[6][128]; // = *(wchar(*)[6][128]) * (uintptr*)0x664CE0;
+int16 CHud::m_ItemToFlash; // = *(int16*)0x95CC82;
 
 // These aren't really in CHud
 float CHud::BigMessageInUse[6];
 float CHud::BigMessageAlpha[6];
 float CHud::BigMessageX[6];
-float &CHud::OddJob2OffTimer = *(float*)0x942FA0;
-int8 &CHud::CounterOnLastFrame = *(int8*)0x95CD67;
-float &CHud::OddJob2XOffset = *(float*)0x8F1B5C;
-int16 &CHud::CounterFlashTimer = *(int16*)0x95CC20;
-int16 &CHud::OddJob2Timer = *(int16*)0x95CC52;
-int8 &CHud::TimerOnLastFrame = *(int8*)0x95CDA7;
-int16 &CHud::OddJob2On = *(int16*)0x95CC78;
-int16 &CHud::TimerFlashTimer = *(int16*)0x95CC6C;
-int16 &CHud::PagerSoundPlayed = *(int16*)0x95CC4A;
-int32 &CHud::SpriteBrightness = *(int32*)0x95CC54;
-float &CHud::PagerXOffset = *(float*)0x941590;
-int16 &CHud::PagerTimer = *(int16*)0x95CC3A;
-int16 &CHud::PagerOn = *(int16*)0x95CCA0;
+float CHud::OddJob2OffTimer; // = *(float*)0x942FA0;
+bool CHud::CounterOnLastFrame; // = *(int8*)0x95CD67;
+float CHud::OddJob2XOffset; // = *(float*)0x8F1B5C;
+uint16 CHud::CounterFlashTimer; // = *(int16*)0x95CC20;
+uint16 CHud::OddJob2Timer; // = *(int16*)0x95CC52;
+bool CHud::TimerOnLastFrame; //= *(int8*)0x95CDA7;
+int16 CHud::OddJob2On; //= *(int16*)0x95CC78;
+uint16 CHud::TimerFlashTimer; //= *(int16*)0x95CC6C;
+int16 CHud::PagerSoundPlayed; //= *(int16*)0x95CC4A;
+int32 CHud::SpriteBrightness; //= *(int32*)0x95CC54;
+float CHud::PagerXOffset; //= *(float*)0x941590;
+int16 CHud::PagerTimer; //= *(int16*)0x95CC3A;
+int16 CHud::PagerOn; //= *(int16*)0x95CCA0;
 
-CSprite2d *CHud::Sprites = (CSprite2d*)0x95CB9C;
+CSprite2d CHud::Sprites[NUM_HUD_SPRITES]; //  = (CSprite2d*)0x95CB9C;
 
 struct
 {
@@ -93,14 +85,14 @@ struct
 	{"detonator", "detonator_mask"},
 	{"", ""},
 	{"", ""},
-	{"radardisc", "radardiscm"},
+	{"radardisc", "radardisc"},
 	{"pager", "pagerm"},
 	{"", ""},
 	{"", ""},
 	{"bleeder", ""},
 	{"sitesniper", "sitesniperm"},
 	{"siteM16", "siteM16m"},
-	{"siterocket", "siterocketm"}
+	{"siterocket", "siterocket"}
 };
 
 RwTexture *&gpSniperSightTex = *(RwTexture**)0x8F5834;
@@ -418,7 +410,7 @@ void CHud::Draw()
 			DrawZoneName
 		*/
 		if (m_pZoneName) {
-			float fZoneAlpha = 0.0f;
+			float fZoneAlpha = 255.0f;
 
 			if (m_pZoneName != m_pLastZoneName) {
 				switch (m_ZoneState) {
@@ -432,7 +424,7 @@ void CHud::Draw()
 				case 2:
 				case 3:
 				case 4:
-					m_ZoneNameTimer = 0;
+					m_ZoneNameTimer = 5;
 					m_ZoneState = 4;
 					break;
 				default:
@@ -444,6 +436,7 @@ void CHud::Draw()
 			if (m_ZoneState) {
 				switch (m_ZoneState) {
 				case 1:
+					m_ZoneFadeTimer = 1000;
 					if (m_ZoneNameTimer > 10000) {
 						m_ZoneFadeTimer = 1000;
 						m_ZoneState = 3;
@@ -471,7 +464,6 @@ void CHud::Draw()
 					if (m_ZoneFadeTimer < 0) {
 						m_ZoneFadeTimer = 0;
 						m_ZoneToPrint = m_pLastZoneName;
-						m_ZoneNameTimer = 0;
 						m_ZoneState = 2;
 					}
 					fZoneAlpha = m_ZoneFadeTimer * 0.001f * 255.0f;
@@ -503,12 +495,6 @@ void CHud::Draw()
 				}
 			}
 		}
-		/*else {
-			m_pLastZoneName = nil;
-			m_ZoneState = 0;
-			m_ZoneFadeTimer = 0;
-			m_ZoneNameTimer = 0;
-		}*/
 
 		/*
 			DrawVehicleName
@@ -636,9 +622,9 @@ void CHud::Draw()
 		wchar sTimer[16];
 
 		if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bTimerProcessed)
-			TimerOnLastFrame = 0;
+			TimerOnLastFrame = false;
 		if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bCounterProcessed)
-			CounterOnLastFrame = 0;
+			CounterOnLastFrame = false;
 
 #ifdef FIX_BUGS
 #define TIMER_RIGHT_OFFSET 34.0f // Taken from VC frenzy timer
@@ -650,7 +636,7 @@ void CHud::Draw()
 				if (!TimerOnLastFrame)
 					TimerFlashTimer = 1;
 
-				TimerOnLastFrame = 1;
+				TimerOnLastFrame = true;
 
 				if (TimerFlashTimer) {
 					if (++TimerFlashTimer > 50)
@@ -688,7 +674,7 @@ void CHud::Draw()
 				if (!CounterOnLastFrame)
 					CounterFlashTimer = 1;
 
-				CounterOnLastFrame = 1;
+				CounterOnLastFrame = true;
 
 				if (CounterFlashTimer) {
 					if (++CounterFlashTimer > 50)
@@ -742,11 +728,9 @@ void CHud::Draw()
 		/*
 			DrawPager
 		*/
-		if (!m_PagerMessage[0]) {
-			if (PagerOn == 1) {
-				PagerSoundPlayed = false;
-				PagerOn = 2;
-			}
+		if (!m_PagerMessage[0] && PagerOn == 1) {
+			PagerSoundPlayed = false;
+			PagerOn = 2;
 		}
 		if (m_PagerMessage[0] || PagerOn == 2) {
 			if (!PagerOn) {
@@ -755,7 +739,7 @@ void CHud::Draw()
 			}
 			if (PagerOn == 1) {
 				if (PagerXOffset > 0.0f) {
-					float fStep = PagerXOffset * 0.05f;
+					float fStep = PagerXOffset * 0.1f;
 					if (fStep > 10.0f)
 						fStep = 10.0f;
 					PagerXOffset -= fStep * CTimer::GetTimeStep();
@@ -766,10 +750,10 @@ void CHud::Draw()
 				}
 			}
 			else if (PagerOn == 2) {
-				float fStep = PagerXOffset * 0.05f;
+				float fStep = PagerXOffset * 0.1f;
 				if (fStep < 2.0f)
 					fStep = 2.0f;
-				PagerXOffset += fStep * CTimer::GetTimeStep();
+				PagerXOffset += fStep;
 				if (PagerXOffset > 150.0f) {
 					PagerXOffset = 150.0f;
 					PagerOn = 0;
@@ -818,9 +802,7 @@ void CHud::Draw()
 		DrawScriptText
 	*/
 	if (!CTimer::GetIsUserPaused()) {
-		CTextLine* IntroText = CTheScripts::IntroTextLines;
-
-		for (int i = 0; i < MAX_NUM_INTRO_TEXT_LINES; i++) {
+		for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroTextLines); i++) {
 			if (CTheScripts::IntroTextLines[i].m_Text[0] && CTheScripts::IntroTextLines[i].m_bTextBeforeFade) {
 				CFont::SetScale(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fScaleX), SCREEN_SCALE_Y(CTheScripts::IntroTextLines[i].m_fScaleY * 0.5f));
 				CFont::SetColor(CTheScripts::IntroTextLines[i].m_sColor);
@@ -861,31 +843,31 @@ void CHud::Draw()
 					CFont::SetPropOff();
 
 				CFont::SetFontStyle(FONTJAP(CTheScripts::IntroTextLines[i].m_nFont));
-				CFont::PrintString(SCREEN_SCALE_X(640.0f - CTheScripts::IntroTextLines[i].m_fAtX), SCREEN_SCALE_Y(448.0f - CTheScripts::IntroTextLines[i].m_fAtY), IntroText->m_Text);
+				CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - CTheScripts::IntroTextLines[i].m_fAtX), SCREEN_SCALE_Y(DEFAULT_SCREEN_HEIGHT - CTheScripts::IntroTextLines[i].m_fAtY), CTheScripts::IntroTextLines[i].m_Text);
 			}
 		}
+		for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroRectangles); i++) {
+			intro_script_rectangle &IntroRect = CTheScripts::IntroRectangles[i];
 
-		CScriptRectangle* IntroRect = CTheScripts::IntroRectangles;
-
-		for (int i = 0; i < 16; i++) {
-			if (CTheScripts::IntroRectangles[i].m_bIsUsed && CTheScripts::IntroRectangles[i].m_bBeforeFade) {
-				if (CTheScripts::IntroRectangles[i].m_nTextureId >= 0) {
+			// Yeah, top and bottom changed place. R* vision
+			if (IntroRect.m_bIsUsed && IntroRect.m_bBeforeFade) {
+				if (IntroRect.m_nTextureId >= 0) {
 					CRect rect = {
-						CTheScripts::IntroRectangles[i].m_sRect.left,
-						CTheScripts::IntroRectangles[i].m_sRect.bottom,
-						CTheScripts::IntroRectangles[i].m_sRect.right,
-						CTheScripts::IntroRectangles[i].m_sRect.bottom };
+						IntroRect.m_sRect.left,
+						IntroRect.m_sRect.top,
+						IntroRect.m_sRect.right,
+						IntroRect.m_sRect.bottom };
 
-					CTheScripts::ScriptSprites[CTheScripts::IntroRectangles[i].m_nTextureId].Draw(rect, IntroRect->m_sColor);
+					CTheScripts::ScriptSprites[IntroRect.m_nTextureId].Draw(rect, IntroRect.m_sColor);
 				}
 				else {
 					CRect rect = {
-						CTheScripts::IntroRectangles[i].m_sRect.left,
-						CTheScripts::IntroRectangles[i].m_sRect.bottom,
-						CTheScripts::IntroRectangles[i].m_sRect.right,
-						CTheScripts::IntroRectangles[i].m_sRect.bottom };
+						IntroRect.m_sRect.left,
+						IntroRect.m_sRect.top,
+						IntroRect.m_sRect.right,
+						IntroRect.m_sRect.bottom };
 
-					CSprite2d::DrawRect(rect, IntroRect->m_sColor);
+					CSprite2d::DrawRect(rect, IntroRect.m_sColor);
 				}
 			}
 		}
@@ -931,7 +913,7 @@ void CHud::Draw()
 				CFont::SetCentreSize(SCREEN_SCALE_X(615.0f));
 				CFont::SetFontStyle(FONT_HEADING);
 
-				if (BigMessageX[0] >= (SCREEN_WIDTH - 20)) {
+				if (BigMessageX[0] >= SCREEN_SCALE_FROM_RIGHT(20.0f)) {
 					BigMessageInUse[0] += CTimer::GetTimeStep();
 
 					if (BigMessageInUse[0] >= 120.0f) {
@@ -948,7 +930,7 @@ void CHud::Draw()
 					BigMessageX[0] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
 					BigMessageAlpha[0] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
 
-					if (BigMessageAlpha[0] >= 255.0f)
+					if (BigMessageAlpha[0] > 255.0f)
 						BigMessageAlpha[0] = 255.0f;
 				}
 
@@ -992,7 +974,7 @@ void CHud::Draw()
 				CFont::SetFontStyle(FONT_HEADING);
 
 				CFont::SetColor(CRGBA(0, 0, 0, BigMessageAlpha[2]));
-				CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f + 4.0f), SCREEN_SCALE_FROM_BOTTOM(78.0f), m_BigMessage[2]);
+				CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f - 4.0f), SCREEN_SCALE_FROM_BOTTOM(78.0f), m_BigMessage[2]);
 
 				CFont::SetColor(CRGBA(170, 123, 87, BigMessageAlpha[2]));
 				CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(82.0f), m_BigMessage[2]);
@@ -1021,7 +1003,7 @@ void CHud::DrawAfterFade()
 				m_HelpMessageState = 2;
 				m_HelpMessageTimer = 0;
 				CMessages::WideStringCopy(m_HelpMessageToPrint, m_HelpMessage, 256);
-				m_HelpMessageDisplayTime = CMessages::GetWideStringLength(m_HelpMessage) * 0.05f + 3.0f;
+				m_fHelpMessageTime = CMessages::GetWideStringLength(m_HelpMessage) * 0.05f + 3.0f;
 
 				if (TheCamera.m_ScreenReductionPercentage == 0.0f)
 					DMAudio.PlayFrontEndSound(SOUND_A0, 0);
@@ -1039,14 +1021,14 @@ void CHud::DrawAfterFade()
 			CMessages::WideStringCopy(m_LastHelpMessage, m_HelpMessage, 256);
 		}
 
-		float fAlpha = 255.0f;
+		float fAlpha = 225.0f;
 
-		if (m_HelpMessageState) {
+		if (m_HelpMessageState != 0) {
 			switch (m_HelpMessageState) {
 			case 1:
-				fAlpha = 255.0f;
+				fAlpha = 225.0f;
 				m_HelpMessageFadeTimer = 600;
-				if (m_HelpMessageTimer > m_fHelpMessageTime * 1000 || m_HelpMessageQuick && m_HelpMessageTimer > 1500) {
+				if (m_HelpMessageTimer > m_fHelpMessageTime * 1000.0f || m_HelpMessageQuick && m_HelpMessageTimer > 1500.0f) {
 					m_HelpMessageFadeTimer = 600;
 					m_HelpMessageState = 3;
 				}
@@ -1057,24 +1039,24 @@ void CHud::DrawAfterFade()
 					m_HelpMessageState = 1;
 					m_HelpMessageFadeTimer = 0;
 				}
-				fAlpha = m_HelpMessageFadeTimer * 0.001f * 255.0f;
+				fAlpha = m_HelpMessageFadeTimer * 0.001f * 225.0f;
 				break;
 			case 3:
 				m_HelpMessageFadeTimer -= 2 * CTimer::GetTimeStepInMilliseconds();
-				if (m_HelpMessageFadeTimer >= 0) {
+				if (m_HelpMessageFadeTimer < 0) {
 					m_HelpMessageState = 0;
 					m_HelpMessageFadeTimer = 0;
 				}
-				fAlpha = m_HelpMessageFadeTimer * 0.001f * 255.0f;
+				fAlpha = m_HelpMessageFadeTimer * 0.001f * 225.0f;
 				break;
 			case 4:
 				m_HelpMessageFadeTimer -= 2 * CTimer::GetTimeStepInMilliseconds();
-				if (m_HelpMessageFadeTimer >= 0) {
+				if (m_HelpMessageFadeTimer < 0) {
 					m_HelpMessageState = 2;
 					m_HelpMessageFadeTimer = 0;
-					CMessages::WideStringCopy(m_HelpMessageToPrint, m_LastHelpMessage, 400);
+					CMessages::WideStringCopy(m_HelpMessageToPrint, m_LastHelpMessage, 256);
 				}
-				fAlpha = m_HelpMessageFadeTimer * 0.001f * 255.0f;
+				fAlpha = m_HelpMessageFadeTimer * 0.001f * 225.0f;
 				break;
 			default:
 				break;
@@ -1093,6 +1075,7 @@ void CHud::DrawAfterFade()
 			else
 				CFont::SetScale(SCREEN_SCALE_X(0.52f), SCREEN_SCALE_Y(1.1f));
 
+			CFont::SetColor(CRGBA(175, 175, 175, 255));
 			CFont::SetJustifyOff();
 			if (CFont::LanguageSet == FONT_LANGSET_JAPANESE) 
 				CFont::SetWrapx(SCREEN_SCALE_X(229.0f + 26.0f - 4.0f));
@@ -1101,14 +1084,69 @@ void CHud::DrawAfterFade()
 			CFont::SetFontStyle(FONTJAP(FONT_BANK));
 			CFont::SetBackgroundOn();
 			CFont::SetBackGroundOnlyTextOff();
-			CFont::SetBackgroundColor(CRGBA(0, 0, 0, fAlpha * 0.8f));
-			CFont::SetColor(CRGBA(175, 175, 175, 255));
+			CFont::SetBackgroundColor(CRGBA(0, 0, 0, fAlpha * 0.9f));
 			CFont::PrintString(SCREEN_SCALE_X(26.0f), SCREEN_SCALE_Y(28.0f + (150.0f - PagerXOffset) * 0.6f), CHud::m_HelpMessageToPrint);
 			CFont::SetAlphaFade(255.0f);
 		}
 	}
-	else
-		m_HelpMessageState = 0;
+
+	for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroTextLines); i++) {
+		intro_text_line &line = CTheScripts::IntroTextLines[i];
+		if (line.m_Text[0] != '\0' && !line.m_bTextBeforeFade) {
+			CFont::SetScale(SCREEN_SCALE_X(line.m_fScaleX), SCREEN_SCALE_Y(line.m_fScaleY) / 2);
+
+			CFont::SetColor(line.m_sColor);
+			if (line.m_bJustify)
+				CFont::SetJustifyOn();
+			else
+				CFont::SetJustifyOff();
+
+			if (line.m_bRightJustify)
+				CFont::SetRightJustifyOn();
+			else
+				CFont::SetRightJustifyOff();
+
+			if (line.m_bCentered)
+				CFont::SetCentreOn();
+			else
+				CFont::SetCentreOff();
+
+			CFont::SetWrapx(SCREEN_SCALE_X(line.m_fWrapX));
+			CFont::SetCentreSize(SCREEN_SCALE_X(line.m_fCenterSize));
+			if (line.m_bBackground)
+				CFont::SetBackgroundOn();
+			else
+				CFont::SetBackgroundOff();
+
+			CFont::SetBackgroundColor(line.m_sBackgroundColor);
+			if (line.m_bBackgroundOnly)
+				CFont::SetBackGroundOnlyTextOn();
+			else
+				CFont::SetBackGroundOnlyTextOff();
+
+			if (line.m_bTextProportional)
+				CFont::SetPropOn();
+			else
+				CFont::SetPropOff();
+
+			CFont::SetFontStyle(line.m_nFont);
+			CFont::PrintString(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - line.m_fAtX), SCREEN_SCALE_Y(DEFAULT_SCREEN_HEIGHT - line.m_fAtY), line.m_Text);
+		}
+	}
+	for (int i = 0; i < ARRAY_SIZE(CTheScripts::IntroRectangles); i++) {
+		intro_script_rectangle &rectangle = CTheScripts::IntroRectangles[i];
+		if (rectangle.m_bIsUsed && !rectangle.m_bBeforeFade) {
+
+			// Yeah, top and bottom changed place. R* vision
+			if (rectangle.m_nTextureId >= 0) {
+				CTheScripts::ScriptSprites[rectangle.m_nTextureId].Draw(CRect(rectangle.m_sRect.left, rectangle.m_sRect.bottom,
+					rectangle.m_sRect.right, rectangle.m_sRect.top), rectangle.m_sColor);
+			} else {
+				CSprite2d::DrawRect(CRect(rectangle.m_sRect.left, rectangle.m_sRect.bottom,
+					rectangle.m_sRect.right, rectangle.m_sRect.top), rectangle.m_sColor);
+			}
+		}
+	}
 
 	/*
 		DrawBigMessage2
@@ -1150,10 +1188,9 @@ void CHud::DrawAfterFade()
 	if (OddJob2OffTimer > 0)
 		OddJob2OffTimer -= CTimer::GetTimeStepInMilliseconds();
 
-	static float fStep;
+	float fStep;
 	if (m_BigMessage[5][0] && OddJob2OffTimer <= 0.0f) {
-		if (OddJob2On <= 3) {
-			switch (OddJob2On) {
+		switch (OddJob2On) {
 			case 0:
 				OddJob2On = 1;
 				OddJob2XOffset = 380.0f;
@@ -1164,9 +1201,7 @@ void CHud::DrawAfterFade()
 					OddJob2On = 2;
 				}
 				else {
-					fStep = 40.0f;
-					if ((OddJob2XOffset / 6.0f) <= 40.0f)
-						fStep = OddJob2XOffset / 6.0f;
+					fStep = min(40.0f, OddJob2XOffset / 6.0f);
 					OddJob2XOffset = OddJob2XOffset - fStep;
 				}
 				break;
@@ -1177,9 +1212,7 @@ void CHud::DrawAfterFade()
 				}
 				break;
 			case 3:
-				fStep = 30.0f;
-				if ((OddJob2XOffset / 5.0f) >= 30.0f)
-					fStep = OddJob2XOffset / 5.0f;
+				fStep = max(30.0f, OddJob2XOffset / 5.0f);
 
 				OddJob2XOffset = OddJob2XOffset - fStep;
 
@@ -1190,7 +1223,6 @@ void CHud::DrawAfterFade()
 				break;
 			default:
 				break;
-			}
 		}
 
 		if (!m_BigMessage[1][0]) {
@@ -1224,10 +1256,10 @@ void CHud::DrawAfterFade()
 				CFont::SetScale(SCREEN_SCALE_X(1.04f), SCREEN_SCALE_Y(1.6f));
 
 			CFont::SetPropOn();
-			CFont::SetRightJustifyWrap(-500.0f);
+			CFont::SetRightJustifyWrap(SCREEN_SCALE_X(-500.0f));
 			CFont::SetRightJustifyOn();
 			CFont::SetFontStyle(FONT_HEADING);
-			if (BigMessageX[1] >= (SCREEN_WIDTH - 20)) {
+			if (BigMessageX[1] >= SCREEN_SCALE_FROM_RIGHT(20.0f)) {
 				BigMessageInUse[1] += CTimer::GetTimeStep();
 
 				if (BigMessageInUse[1] >= 120.0f) {
@@ -1238,12 +1270,11 @@ void CHud::DrawAfterFade()
 					m_BigMessage[1][0] = 0;
 					BigMessageAlpha[1] = 0.0f;
 				}
-			}
-			else {
+			} else {
 				BigMessageX[1] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
 				BigMessageAlpha[1] += (CTimer::GetTimeStepInMilliseconds() * 0.3f);
 
-				if (BigMessageAlpha[1] >= 255.0f)
+				if (BigMessageAlpha[1] > 255.0f)
 					BigMessageAlpha[1] = 255.0f;
 			}
 
@@ -1281,7 +1312,7 @@ void CHud::GetRidOfAllHudMessages()
 	m_HelpMessageFadeTimer = 0;
 	m_HelpMessageState = 0;
 	m_HelpMessageQuick = 0;
-	m_HelpMessageDisplayTime = 1.0f;
+	m_fHelpMessageTime = 1.0f;
 	m_VehicleName = nil;
 	m_pLastVehicleName = nil;
 	m_pVehicleNameToPrint = nil;
@@ -1311,7 +1342,7 @@ void CHud::Initialise()
 	CTxdStore::PopCurrentTxd();
 	CTxdStore::SetCurrentTxd(HudTXD);
 
-	for (int i = 0; i < ARRAY_SIZE(WeaponFilenames); i++) {
+	for (int i = 0; i < NUM_HUD_SPRITES; i++) {
 		Sprites[i].SetTexture(WeaponFilenames[i].name, WeaponFilenames[i].mask);
 	}
 
@@ -1322,14 +1353,14 @@ void CHud::Initialise()
 	if (gpRocketSightTex == nil)
 		gpRocketSightTex = RwTextureRead("siterocket", nil);
 
-	CounterOnLastFrame = 0;
+	CounterOnLastFrame = false;
 	m_ItemToFlash = ITEM_NONE;
 	OddJob2Timer = 0;
 	OddJob2OffTimer = 0.0f;
 	OddJob2On = 0;
 	OddJob2XOffset = 0.0f;
 	CounterFlashTimer = 0;
-	TimerOnLastFrame = 0;
+	TimerOnLastFrame = false;
 	TimerFlashTimer = 0;
 	SpriteBrightness = 0;
 	PagerOn = 0;
@@ -1346,14 +1377,14 @@ void CHud::ReInitialise() {
 
 	GetRidOfAllHudMessages();
 
-	CounterOnLastFrame = 0;
+	CounterOnLastFrame = false;
 	m_ItemToFlash = ITEM_NONE;
 	OddJob2Timer = 0;
 	OddJob2OffTimer = 0.0f;
 	OddJob2On = 0;
 	OddJob2XOffset = 0.0f;
 	CounterFlashTimer = 0;
-	TimerOnLastFrame = 0;
+	TimerOnLastFrame = false;
 	TimerFlashTimer = 0;
 	SpriteBrightness = 0;
 	PagerOn = 0;
@@ -1443,7 +1474,7 @@ void CHud::SetZoneName(wchar *name)
 
 void CHud::Shutdown()
 {
-	for (int i = 0; i < ARRAY_SIZE(WeaponFilenames); ++i) {
+	for (int i = 0; i < NUM_HUD_SPRITES; ++i) {
 		Sprites[i].Delete();
 	}
 
diff --git a/src/render/Hud.h b/src/render/Hud.h
index dad3a58d..701e47e2 100644
--- a/src/render/Hud.h
+++ b/src/render/Hud.h
@@ -27,59 +27,60 @@ enum eSprites
 	HUD_RADARDISC = 15,
 	HUD_PAGER = 16,
 	HUD_SITESNIPER = 20,
-	HUD_SITEM16 = 21
+	HUD_SITEM16,
+	HUD_SITEROCKET,
+	NUM_HUD_SPRITES,
 };
 
 class CHud
 {
 public:
-	static CSprite2d *Sprites;
-	static int32 &SpriteBrightness;
+	static CSprite2d Sprites[NUM_HUD_SPRITES];
 	static wchar m_HelpMessage[256];
 	static wchar m_LastHelpMessage[256];
-	static int32 &m_HelpMessageState;
-	static int32 &m_HelpMessageTimer;
-	static int32 &m_HelpMessageFadeTimer;
-	static wchar *m_HelpMessageToPrint;
+	static uint32 m_HelpMessageState;
+	static uint32 m_HelpMessageTimer;
+	static int32 m_HelpMessageFadeTimer;
+	static wchar m_HelpMessageToPrint[256];
 	static float &m_HelpMessageDisplayTime;
-	static float &m_fTextBoxNumLines;
-	static float &m_fHelpMessageTime;
-	static bool	&m_HelpMessageQuick;
-	static int32 m_ZoneState;
+	static float m_fHelpMessageTime;
+	static bool	m_HelpMessageQuick;
+	static uint32 m_ZoneState;
 	static int32 m_ZoneFadeTimer;
-	static int32 m_ZoneNameTimer;
-	static wchar *&m_pZoneName;
+	static uint32 m_ZoneNameTimer;
+	static wchar *m_pZoneName;
 	static wchar *m_pLastZoneName;
 	static wchar *m_ZoneToPrint;
-	static wchar *&m_VehicleName;
+	static wchar *m_VehicleName;
 	static wchar *m_pLastVehicleName;
 	static wchar *m_pVehicleNameToPrint;
-	static int32 m_VehicleState;
+	static uint32 m_VehicleState;
 	static int32 m_VehicleFadeTimer;
-	static int32 m_VehicleNameTimer;
-	static wchar *m_Message;
-	static wchar *m_PagerMessage;
-	static bool &m_Wants_To_Draw_Hud;
-	static bool &m_Wants_To_Draw_3dMarkers;
-	static wchar(&m_BigMessage)[6][128];
-	static int16 &m_ItemToFlash;
+	static uint32 m_VehicleNameTimer;
+	static wchar m_Message[256];
+	static wchar m_PagerMessage[256];
+	static bool m_Wants_To_Draw_Hud;
+	static bool m_Wants_To_Draw_3dMarkers;
+	static wchar m_BigMessage[6][128];
+	static int16 m_ItemToFlash;
 
 	// These aren't really in CHud
 	static float BigMessageInUse[6];
 	static float BigMessageAlpha[6];
 	static float BigMessageX[6];
-	static float &OddJob2OffTimer;
-	static int8 &CounterOnLastFrame;
-	static float &OddJob2XOffset;
-	static int16 &CounterFlashTimer;
-	static int16 &OddJob2Timer;
-	static int8 &TimerOnLastFrame;
-	static int16 &OddJob2On;
-	static int16 &TimerFlashTimer;
-	static int16 &PagerSoundPlayed;
-	static float &PagerXOffset;
-	static int16 &PagerTimer;
-	static int16 &PagerOn;
+	static float OddJob2OffTimer;
+	static bool CounterOnLastFrame;
+	static float OddJob2XOffset;
+	static uint16 CounterFlashTimer;
+	static uint16 OddJob2Timer;
+	static bool TimerOnLastFrame;
+	static int16 OddJob2On;
+	static uint16 TimerFlashTimer;
+	static int16 PagerSoundPlayed;
+	static int32 SpriteBrightness;
+	static float PagerXOffset;
+	static int16 PagerTimer;
+	static int16 PagerOn;
 
 public:
 	static void Draw();
diff --git a/src/render/MBlur.cpp b/src/render/MBlur.cpp
index 1cf27ee0..d28671fa 100644
--- a/src/render/MBlur.cpp
+++ b/src/render/MBlur.cpp
@@ -4,12 +4,13 @@
 #include "Camera.h"
 #include "MBlur.h"
 
+// Originally taken from RW example 'mblur'
+
 RwRaster *&CMBlur::pFrontBuffer = *(RwRaster**)0x8E2C48;
 bool &CMBlur::ms_bJustInitialised = *(bool*)0x95CDAB;
 bool &CMBlur::BlurOn = *(bool*)0x95CDAD;
 
 static RwIm2DVertex Vertex[4];
-//static RwIm2DVertex *Vertex = (RwIm2DVertex*)0x62F780;
 static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 };
 
 void
diff --git a/src/core/PlayerSkin.cpp b/src/render/PlayerSkin.cpp
similarity index 92%
rename from src/core/PlayerSkin.cpp
rename to src/render/PlayerSkin.cpp
index 4f730b90..2cba45fe 100644
--- a/src/core/PlayerSkin.cpp
+++ b/src/render/PlayerSkin.cpp
@@ -1,173 +1,174 @@
-#include "common.h"
-#include "patcher.h"
-#include "main.h"
-#include "PlayerSkin.h"
-#include "TxdStore.h"
-#include "rtbmp.h"
-#include "ClumpModelInfo.h"
-#include "VisibilityPlugins.h"
-#include "World.h"
-#include "PlayerInfo.h"
-#include "CdStream.h"
-#include "FileMgr.h"
-#include "Directory.h"
-#include "RwHelper.h"
-#include "Timer.h"
-#include "Lights.h"
-
-int CPlayerSkin::m_txdSlot;
-
-void
-FindPlayerDff(uint32 &offset, uint32 &size)
-{
-	int file;
-	CDirectory::DirectoryInfo info;
-
-	file = CFileMgr::OpenFile("models\\gta3.dir", "rb");
-
-	do {
-		if (!CFileMgr::Read(file, (char*)&info, sizeof(CDirectory::DirectoryInfo)))
-			return;
-	} while (strcasecmp("player.dff", info.name) != 0);
-
-	offset = info.offset;
-	size = info.size;
-}
-
-void
-LoadPlayerDff(void)
-{
-	RwStream *stream;
-	RwMemory mem;
-	uint32 offset, size;
-	uint8 *buffer;
-	bool streamWasAdded = false;
-
-	if (CdStreamGetNumImages() == 0) {
-		CdStreamAddImage("models\\gta3.img");
-		streamWasAdded = true;
-	}
-
-	FindPlayerDff(offset, size);
-	buffer = (uint8*)RwMallocAlign(size << 11, 2048);
-	CdStreamRead(0, buffer, offset, size);
-	CdStreamSync(0);
-
-	mem.start = buffer;
-	mem.length = size << 11;
-	stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem);
-
-	if (RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
-		gpPlayerClump = RpClumpStreamRead(stream);
-
-	RwStreamClose(stream, &mem);
-	RwFreeAlign(buffer);
-
-	if (streamWasAdded)
-		CdStreamRemoveImages();
-}
-
-void
-CPlayerSkin::Initialise(void)
-{
-	m_txdSlot = CTxdStore::AddTxdSlot("skin");
-	CTxdStore::Create(m_txdSlot);
-	CTxdStore::AddRef(m_txdSlot);
-}
-
-void
-CPlayerSkin::Shutdown(void)
-{
-	CTxdStore::RemoveTxdSlot(m_txdSlot);
-}
-
-RwTexture *
-CPlayerSkin::GetSkinTexture(const char *texName)
-{
-	RwTexture *tex;
-	RwRaster *raster;
-	int32 width, height, depth, format;
-
-	CTxdStore::PushCurrentTxd();
-	CTxdStore::SetCurrentTxd(m_txdSlot);
-	tex = RwTextureRead(texName, NULL);
-	CTxdStore::PopCurrentTxd();
-	if (tex) return tex;
-
-	if (strcmp(DEFAULT_SKIN_NAME, texName) == 0)
-		sprintf(gString, "models\\generic\\player.bmp");
-	else
-		sprintf(gString, "skins\\%s.bmp", texName);
-
-	if (RwImage *image = RtBMPImageRead(gString)) {
-		RwImageFindRasterFormat(image, rwRASTERTYPETEXTURE, &width, &height, &depth, &format);
-		raster = RwRasterCreate(width, height, depth, format);
-		RwRasterSetFromImage(raster, image);
-
-		tex = RwTextureCreate(raster);
-		RwTextureSetName(tex, texName);
-		RwTextureSetFilterMode(tex, rwFILTERLINEAR); // filtering bugfix from VC
-		RwTexDictionaryAddTexture(CTxdStore::GetSlot(m_txdSlot)->texDict, tex);
-
-		RwImageDestroy(image);
-	}
-	return tex;
-}
-
-void
-CPlayerSkin::BeginFrontendSkinEdit(void)
-{
-	LoadPlayerDff();
-	RpClumpForAllAtomics(gpPlayerClump, CClumpModelInfo::SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB);
-	CWorld::Players[0].LoadPlayerSkin();
-	gOldFov = CDraw::GetFOV();
-	CDraw::SetFOV(30.0f);
-}
-
-void
-CPlayerSkin::EndFrontendSkinEdit(void)
-{
-	RpClumpDestroy(gpPlayerClump);
-	gpPlayerClump = NULL;
-	CDraw::SetFOV(gOldFov);
-}
-
-void
-CPlayerSkin::RenderFrontendSkinEdit(void)
-{
-	static float rotation = 0.0f;
-	RwRGBAReal AmbientColor = { 0.65f, 0.65f, 0.65f, 1.0f };
-	RwV3d pos = { 1.35f, 0.35f, 7.725f };
-	const RwV3d axis1 = { 1.0f, 0.0f, 0.0f };
-	const RwV3d axis2 = { 0.0f, 0.0f, 1.0f };
-	static uint32 LastFlash = 0;
-
-#ifdef ASPECT_RATIO_SCALE
-	pos.x = 1.35f * (SCREEN_ASPECT_RATIO / DEFAULT_ASPECT_RATIO);
-#endif
-
-	RwFrame *frame = RpClumpGetFrame(gpPlayerClump);
-
-	if (CTimer::GetTimeInMillisecondsPauseMode() - LastFlash > 7) {
-		rotation += 2.0f;
-		if (rotation > 360.0f)
-			rotation -= 360.0f;
-		LastFlash = CTimer::GetTimeInMillisecondsPauseMode();
-	}
-	RwFrameTransform(frame, RwFrameGetMatrix(RwCameraGetFrame(Scene.camera)), rwCOMBINEREPLACE);
-	RwFrameTranslate(frame, &pos, rwCOMBINEPRECONCAT);
-	RwFrameRotate(frame, &axis1, -90.0f, rwCOMBINEPRECONCAT);
-	RwFrameRotate(frame, &axis2, rotation, rwCOMBINEPRECONCAT);
-	RwFrameUpdateObjects(frame);
-	SetAmbientColours(&AmbientColor);
-	RpClumpRender(gpPlayerClump);
-}
-
-STARTPATCHES
-InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP);
-InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP);
-InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP);
-InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP);
-InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP);
-InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP);
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "PlayerSkin.h"
+#include "TxdStore.h"
+#include "rtbmp.h"
+#include "ClumpModelInfo.h"
+#include "VisibilityPlugins.h"
+#include "World.h"
+#include "PlayerInfo.h"
+#include "CdStream.h"
+#include "FileMgr.h"
+#include "Directory.h"
+#include "RwHelper.h"
+#include "Timer.h"
+#include "Lights.h"
+
+RpClump *gpPlayerClump;
+float gOldFov;
+
+int CPlayerSkin::m_txdSlot;
+
+void
+FindPlayerDff(uint32 &offset, uint32 &size)
+{
+	int file;
+	CDirectory::DirectoryInfo info;
+
+	file = CFileMgr::OpenFile("models\\gta3.dir", "rb");
+
+	do {
+		if (!CFileMgr::Read(file, (char*)&info, sizeof(CDirectory::DirectoryInfo)))
+			return;
+	} while (strcasecmp("player.dff", info.name) != 0);
+
+	offset = info.offset;
+	size = info.size;
+}
+
+void
+LoadPlayerDff(void)
+{
+	RwStream *stream;
+	RwMemory mem;
+	uint32 offset, size;
+	uint8 *buffer;
+	bool streamWasAdded = false;
+
+	if (CdStreamGetNumImages() == 0) {
+		CdStreamAddImage("models\\gta3.img");
+		streamWasAdded = true;
+	}
+
+	FindPlayerDff(offset, size);
+	buffer = (uint8*)RwMallocAlign(size << 11, 2048);
+	CdStreamRead(0, buffer, offset, size);
+	CdStreamSync(0);
+
+	mem.start = buffer;
+	mem.length = size << 11;
+	stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem);
+
+	if (RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
+		gpPlayerClump = RpClumpStreamRead(stream);
+
+	RwStreamClose(stream, &mem);
+	RwFreeAlign(buffer);
+
+	if (streamWasAdded)
+		CdStreamRemoveImages();
+}
+
+void
+CPlayerSkin::Initialise(void)
+{
+	m_txdSlot = CTxdStore::AddTxdSlot("skin");
+	CTxdStore::Create(m_txdSlot);
+	CTxdStore::AddRef(m_txdSlot);
+}
+
+void
+CPlayerSkin::Shutdown(void)
+{
+	CTxdStore::RemoveTxdSlot(m_txdSlot);
+}
+
+RwTexture *
+CPlayerSkin::GetSkinTexture(const char *texName)
+{
+	RwTexture *tex;
+	RwRaster *raster;
+	int32 width, height, depth, format;
+
+	CTxdStore::PushCurrentTxd();
+	CTxdStore::SetCurrentTxd(m_txdSlot);
+	tex = RwTextureRead(texName, NULL);
+	CTxdStore::PopCurrentTxd();
+	if (tex != nil) return tex;
+
+	if (strcmp(DEFAULT_SKIN_NAME, texName) == 0)
+		sprintf(gString, "models\\generic\\player.bmp");
+	else
+		sprintf(gString, "skins\\%s.bmp", texName);
+
+	if (RwImage *image = RtBMPImageRead(gString)) {
+		RwImageFindRasterFormat(image, rwRASTERTYPETEXTURE, &width, &height, &depth, &format);
+		raster = RwRasterCreate(width, height, depth, format);
+		RwRasterSetFromImage(raster, image);
+
+		tex = RwTextureCreate(raster);
+		RwTextureSetName(tex, texName);
+#ifdef FIX_BUGS
+		RwTextureSetFilterMode(tex, rwFILTERLINEAR); // filtering bugfix from VC
+#endif
+		RwTexDictionaryAddTexture(CTxdStore::GetSlot(m_txdSlot)->texDict, tex);
+
+		RwImageDestroy(image);
+	}
+	return tex;
+}
+
+void
+CPlayerSkin::BeginFrontendSkinEdit(void)
+{
+	LoadPlayerDff();
+	RpClumpForAllAtomics(gpPlayerClump, CClumpModelInfo::SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB);
+	CWorld::Players[0].LoadPlayerSkin();
+	gOldFov = CDraw::GetFOV();
+	CDraw::SetFOV(30.0f);
+}
+
+void
+CPlayerSkin::EndFrontendSkinEdit(void)
+{
+	RpClumpDestroy(gpPlayerClump);
+	gpPlayerClump = NULL;
+	CDraw::SetFOV(gOldFov);
+}
+
+void
+CPlayerSkin::RenderFrontendSkinEdit(void)
+{
+	static float rotation = 0.0f;
+	RwRGBAReal AmbientColor = { 0.65f, 0.65f, 0.65f, 1.0f };
+	const RwV3d pos = { 1.35f, 0.35f, 7.725f };
+	const RwV3d axis1 = { 1.0f, 0.0f, 0.0f };
+	const RwV3d axis2 = { 0.0f, 0.0f, 1.0f };
+	static uint32 LastFlash = 0;
+
+	RwFrame *frame = RpClumpGetFrame(gpPlayerClump);
+
+	if (CTimer::GetTimeInMillisecondsPauseMode() - LastFlash > 7) {
+		rotation += 2.0f;
+		if (rotation > 360.0f)
+			rotation -= 360.0f;
+		LastFlash = CTimer::GetTimeInMillisecondsPauseMode();
+	}
+	RwFrameTransform(frame, RwFrameGetMatrix(RwCameraGetFrame(Scene.camera)), rwCOMBINEREPLACE);
+	RwFrameTranslate(frame, &pos, rwCOMBINEPRECONCAT);
+	RwFrameRotate(frame, &axis1, -90.0f, rwCOMBINEPRECONCAT);
+	RwFrameRotate(frame, &axis2, rotation, rwCOMBINEPRECONCAT);
+	RwFrameUpdateObjects(frame);
+	SetAmbientColours(&AmbientColor);
+	RpClumpRender(gpPlayerClump);
+}
+
+STARTPATCHES
+InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP);
+InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP);
+InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP);
+InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP);
+InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/core/PlayerSkin.h b/src/render/PlayerSkin.h
similarity index 64%
rename from src/core/PlayerSkin.h
rename to src/render/PlayerSkin.h
index 2d82ec12..e0214ce0 100644
--- a/src/core/PlayerSkin.h
+++ b/src/render/PlayerSkin.h
@@ -2,12 +2,6 @@
 
 #define DEFAULT_SKIN_NAME "$$\"\""
 
-static RpClump *gpPlayerClump;// = *(RpClump**)0x660FF8;
-static float gOldFov;// = *(float*)0x660FFC;
-
-void LoadPlayerDff(void);
-void FindPlayerDff(uint32 &offset, uint32 &size);
-
 class CPlayerSkin
 {
 	static int m_txdSlot;
diff --git a/src/render/Renderer.h b/src/render/Renderer.h
index 89fc23cb..42c154ec 100644
--- a/src/render/Renderer.h
+++ b/src/render/Renderer.h
@@ -29,7 +29,7 @@ class CRenderer
 	static CVehicle *&m_pFirstPersonVehicle;
 
 public:
-	static float &ms_lodDistScale;	// defined in Frontend.cpp
+	static float ms_lodDistScale;	// defined in Frontend.cpp
 	static bool &m_loadingPriority;
 
 	static void Init(void);
diff --git a/src/render/Rubbish.cpp b/src/render/Rubbish.cpp
index a52e59a0..65d8b2dd 100644
--- a/src/render/Rubbish.cpp
+++ b/src/render/Rubbish.cpp
@@ -1,10 +1,420 @@
 #include "common.h"
+#include "main.h"
 #include "patcher.h"
+#include "General.h"
+#include "Timer.h"
+#include "Weather.h"
+#include "Camera.h"
+#include "World.h"
+#include "Vehicle.h"
+#include "ZoneCull.h"
+#include "TxdStore.h"
+#include "RenderBuffer.h"
 #include "Rubbish.h"
 
-WRAPPER void CRubbish::Render(void) { EAXJMP(0x512190); }
-WRAPPER void CRubbish::StirUp(CVehicle *veh) { EAXJMP(0x512690); }
-WRAPPER void CRubbish::Update(void) { EAXJMP(0x511B90); }
-WRAPPER void CRubbish::SetVisibility(bool) { EAXJMP(0x512AA0); }
-WRAPPER void CRubbish::Init(void) { EAXJMP(0x511940); }
-WRAPPER void CRubbish::Shutdown(void) { EAXJMP(0x511B50); }
+#define RUBBISH_MAX_DIST (18.0f)
+#define RUBBISH_FADE_DIST (16.5f)
+
+RwTexture *gpRubbishTexture[4];
+RwImVertexIndex RubbishIndexList[6];
+RwImVertexIndex RubbishIndexList2[6];	// unused
+RwIm3DVertex RubbishVertices[4];
+bool CRubbish::bRubbishInvisible;
+int CRubbish::RubbishVisibility;
+COneSheet CRubbish::aSheets[NUM_RUBBISH_SHEETS];
+COneSheet CRubbish::StartEmptyList;
+COneSheet CRubbish::EndEmptyList;
+COneSheet CRubbish::StartStaticsList;
+COneSheet CRubbish::EndStaticsList;
+COneSheet CRubbish::StartMoversList;
+COneSheet CRubbish::EndMoversList;
+
+
+void
+COneSheet::AddToList(COneSheet *list)
+{
+	this->m_next = list->m_next;
+	this->m_prev = list;
+	list->m_next = this;
+	this->m_next->m_prev = this;
+}
+
+void
+COneSheet::RemoveFromList(void)
+{
+	m_next->m_prev = m_prev;
+	m_prev->m_next = m_next;
+}
+
+
+void
+CRubbish::Render(void)
+{
+	int type;
+
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+
+	for(type = 0; type < 4; type++){
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRubbishTexture[type]));
+
+		TempBufferIndicesStored = 0;
+		TempBufferVerticesStored = 0;
+
+		COneSheet *sheet;
+		for(sheet = &aSheets[type*NUM_RUBBISH_SHEETS / 4];
+		    sheet < &aSheets[(type+1)*NUM_RUBBISH_SHEETS / 4];
+		    sheet++){
+			if(sheet->m_state == 0)
+				continue;
+
+			uint32 alpha = 128;
+			CVector pos;
+			if(sheet->m_state == 1){
+				pos = sheet->m_basePos;
+				if(!sheet->m_isVisible)
+					alpha = 0;
+			}else{
+				pos = sheet->m_animatedPos;
+				// Not fully visible during animation, calculate current alpha
+				if(!sheet->m_isVisible || !sheet->m_targetIsVisible){
+					float t = (float)(CTimer::GetTimeInMilliseconds() - sheet->m_moveStart)/sheet->m_moveDuration;
+					float f1 = sheet->m_isVisible ? 1.0f-t : 0.0f;
+					float f2 = sheet->m_targetIsVisible ? t : 0.0f;
+					alpha = 128 * (f1+f2);
+				}
+			}
+
+			float camDist = (pos - TheCamera.GetPosition()).Magnitude2D();
+			if(camDist < RUBBISH_MAX_DIST){
+				if(camDist >= RUBBISH_FADE_DIST)
+					alpha -= alpha*(camDist-RUBBISH_FADE_DIST)/(RUBBISH_MAX_DIST-RUBBISH_FADE_DIST);
+				alpha = (RubbishVisibility*alpha)/256;
+
+				float vx = Sin(sheet->m_angle) * 0.4f;
+				float vy = Cos(sheet->m_angle) * 0.4f;
+
+				int v = TempBufferVerticesStored;
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], pos.x + vx, pos.y + vy, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], 255, 255, 255, alpha);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], pos.x - vy, pos.y + vx, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], 255, 255, 255, alpha);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], pos.x + vy, pos.y - vx, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], 255, 255, 255, alpha);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], pos.x - vx, pos.y - vy, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], 255, 255, 255, alpha);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], 0.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], 0.0f);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], 1.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], 0.0f);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], 0.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], 1.0f);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], 1.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], 1.0f);
+
+				int i = TempBufferIndicesStored;
+				TempBufferRenderIndexList[i+0] = RubbishIndexList[0] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+1] = RubbishIndexList[1] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+2] = RubbishIndexList[2] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+3] = RubbishIndexList[3] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+4] = RubbishIndexList[4] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+5] = RubbishIndexList[5] + TempBufferVerticesStored;
+				TempBufferVerticesStored += 4;
+				TempBufferIndicesStored += 6;
+			}
+		}
+
+		if(TempBufferIndicesStored != 0){
+			LittleTest();
+			if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+				RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+				RwIm3DEnd();
+			}
+		}
+	}
+
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+}
+
+void
+CRubbish::StirUp(CVehicle *veh)
+{
+	if((CTimer::GetFrameCounter() ^ (veh->m_randomSeed&3)) == 0)
+		return;
+
+	if(Abs(veh->GetPosition().x - TheCamera.GetPosition().x) < 20.0f &&
+	   Abs(veh->GetPosition().y - TheCamera.GetPosition().y) < 20.0f)
+		if(Abs(veh->GetMoveSpeed().x) > 0.05f || Abs(veh->GetMoveSpeed().y) > 0.05f){
+			float speed = veh->GetMoveSpeed().Magnitude2D();
+			if(speed > 0.05f){
+				bool movingForward = DotProduct2D(veh->GetMoveSpeed(), veh->GetForward()) > 0.0f;
+				COneSheet *sheet = StartStaticsList.m_next;
+				CVector2D size = veh->GetColModel()->boundingBox.max;
+
+				// Check all static sheets
+				while(sheet != &EndStaticsList){
+					COneSheet *next = sheet->m_next;
+					CVector2D carToSheet = sheet->m_basePos - veh->GetPosition();
+					float distFwd = DotProduct2D(carToSheet, veh->GetForward());
+
+					// sheet has to be a bit behind car
+					if(movingForward && distFwd < -0.5f*size.y && distFwd > -1.5f*size.y ||
+					   !movingForward && distFwd > 0.5f*size.y && distFwd < 1.5f*size.y){
+						float distSide = Abs(DotProduct2D(carToSheet, veh->GetRight()));
+						if(distSide < 1.5*size.x){
+							// Check with higher speed for sheet directly behind car
+							float speedToCheck = distSide < size.x ? speed : speed*0.5f;
+							if(speedToCheck > 0.05f){
+								sheet->m_state = 2;
+								if(speedToCheck > 0.15f)
+									sheet->m_animationType = 2;
+								else
+									sheet->m_animationType = 1;
+								sheet->m_moveDuration = 2000;
+								sheet->m_xDist = veh->GetMoveSpeed().x;
+								sheet->m_yDist = veh->GetMoveSpeed().y;
+								float dist = Sqrt(SQR(sheet->m_xDist)+SQR(sheet->m_yDist));
+								sheet->m_xDist *= 25.0f*speed/dist;
+								sheet->m_yDist *= 25.0f*speed/dist;
+								sheet->m_animHeight = 3.0f*speed;
+								sheet->m_moveStart = CTimer::GetTimeInMilliseconds();
+								float tx = sheet->m_basePos.x + sheet->m_xDist;
+								float ty = sheet->m_basePos.y + sheet->m_yDist;
+								float tz = sheet->m_basePos.z + 3.0f;
+								sheet->m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, nil) + 0.1f;
+								sheet->RemoveFromList();
+								sheet->AddToList(&StartMoversList);
+							}
+						}
+					}
+
+					sheet = next;
+				}
+			}
+		}
+}
+
+static float aAnimations[3][34] = {
+	{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+	  0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+
+	// Normal move
+	{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.86f, 0.9f, 0.93f, 0.95f, 0.96f, 0.97f, 0.98f, 0.99f, 1.0f,	// XY movemnt
+	  0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 },	// Z movement
+
+	// Stirred up by fast vehicle
+	{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.95f, 1.1f, 1.15f, 1.18f, 1.15f, 1.1f, 1.05f, 1.03f, 1.0f,
+	  0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }
+};
+
+void
+CRubbish::Update(void)
+{
+	bool foundGround;
+
+	// FRAMETIME
+	if(bRubbishInvisible)
+		RubbishVisibility = max(RubbishVisibility-5, 0);
+	else
+		RubbishVisibility = min(RubbishVisibility+5, 255);
+
+	// Spawn a new sheet
+	COneSheet *sheet = StartEmptyList.m_next;
+	if(sheet != &EndEmptyList){
+		float spawnDist;
+		float spawnAngle;
+
+		spawnDist = (CGeneral::GetRandomNumber()&0xFF)/256.0f + RUBBISH_MAX_DIST;
+		uint8 r = CGeneral::GetRandomNumber();
+		if(r&1)
+			spawnAngle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
+		else
+			spawnAngle = (r-128)/160.0f + TheCamera.Orientation;
+		sheet->m_basePos.x = TheCamera.GetPosition().x + spawnDist*Sin(spawnAngle);
+		sheet->m_basePos.y = TheCamera.GetPosition().y + spawnDist*Cos(spawnAngle);
+		sheet->m_basePos.z = CWorld::FindGroundZFor3DCoord(sheet->m_basePos.x, sheet->m_basePos.y, TheCamera.GetPosition().z, &foundGround) + 0.1f;
+		if(foundGround){
+			// Found ground, so add to statics list
+			sheet->m_angle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
+			sheet->m_state = 1;
+			if(CCullZones::FindAttributesForCoors(sheet->m_basePos, nil) & ATTRZONE_NORAIN)
+				sheet->m_isVisible = false;
+			else
+				sheet->m_isVisible = true;
+			sheet->RemoveFromList();
+			sheet->AddToList(&StartStaticsList);
+		}
+	}
+
+	// Process animation
+	sheet = StartMoversList.m_next;
+	while(sheet != &EndMoversList){
+		uint32 currentTime = CTimer::GetTimeInMilliseconds() - sheet->m_moveStart;
+		if(currentTime < sheet->m_moveDuration){
+			// Animation
+			int step = 16 * currentTime / sheet->m_moveDuration;	// 16 steps in animation
+			int stepTime = sheet->m_moveDuration/16;	// time in each step
+			float s = (float)(currentTime - stepTime*step) / stepTime;	// position on step
+			float t = (float)currentTime / sheet->m_moveDuration;	// position on total animation
+			// factors for xy and z-movment
+			float fxy = aAnimations[sheet->m_animationType][step]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1]*s;
+			float fz = aAnimations[sheet->m_animationType][step+17]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1+17]*s;
+			sheet->m_animatedPos.x = sheet->m_basePos.x + fxy*sheet->m_xDist;
+			sheet->m_animatedPos.y = sheet->m_basePos.y + fxy*sheet->m_yDist;
+			sheet->m_animatedPos.z = (1.0f-t)*sheet->m_basePos.z + t*sheet->m_targetZ + fz*sheet->m_animHeight;
+			sheet->m_angle += CTimer::GetTimeStep()*0.04f;
+			if(sheet->m_angle > 6.28f)
+				sheet->m_angle -= 6.28f;
+			sheet = sheet->m_next;
+		}else{
+			// End of animation, back into statics list
+			sheet->m_basePos.x += sheet->m_xDist;
+			sheet->m_basePos.y += sheet->m_yDist;
+			sheet->m_basePos.z = sheet->m_targetZ;
+			sheet->m_state = 1;
+			sheet->m_isVisible = sheet->m_targetIsVisible;
+
+			COneSheet *next = sheet->m_next;
+			sheet->RemoveFromList();
+			sheet->AddToList(&StartStaticsList);
+			sheet = next;
+		}
+	}
+
+	// Stir up a sheet by wind
+	// FRAMETIME
+	int freq;
+	if(CWeather::Wind < 0.1f)
+		freq = 31;
+	else if(CWeather::Wind < 0.4f)
+		freq = 7;
+	else if(CWeather::Wind < 0.7f)
+		freq = 1;
+	else
+		freq = 0;
+	if((CTimer::GetFrameCounter() & freq) == 0){
+		// Pick a random sheet and set animation state if static
+		int i = CGeneral::GetRandomNumber() % NUM_RUBBISH_SHEETS;
+		if(aSheets[i].m_state == 1){
+			aSheets[i].m_moveStart = CTimer::GetTimeInMilliseconds();
+			aSheets[i].m_moveDuration = CWeather::Wind*1500.0f + 1000.0f;
+			aSheets[i].m_animHeight = 0.2f;
+			aSheets[i].m_xDist = 3.0f*CWeather::Wind;
+			aSheets[i].m_yDist = 3.0f*CWeather::Wind;
+			// Check if target position is ok
+			float tx = aSheets[i].m_basePos.x + aSheets[i].m_xDist;
+			float ty = aSheets[i].m_basePos.y + aSheets[i].m_yDist;
+			float tz = aSheets[i].m_basePos.z + 3.0f;
+			aSheets[i].m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, &foundGround) + 0.1f;
+			if(CCullZones::FindAttributesForCoors(CVector(tx, ty, aSheets[i].m_targetZ), nil) & ATTRZONE_NORAIN)
+				aSheets[i].m_targetIsVisible = false;
+			else
+				aSheets[i].m_targetIsVisible = true;
+			if(foundGround){
+				// start animation
+				aSheets[i].m_state = 2;
+				aSheets[i].m_animationType = 1;
+				aSheets[i].RemoveFromList();
+				aSheets[i].AddToList(&StartMoversList);
+			}
+		}
+	}
+
+	// Remove sheets that are too far away
+	int i = (CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4))*4;
+	int last = ((CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4)) + 1)*4;
+	for(; i < last; i++){
+		if(aSheets[i].m_state == 1 &&
+		   (aSheets[i].m_basePos - TheCamera.GetPosition()).MagnitudeSqr2D() > SQR(RUBBISH_MAX_DIST+1.0f)){
+			aSheets[i].m_state = 0;
+			aSheets[i].RemoveFromList();
+			aSheets[i].AddToList(&StartEmptyList);
+		}
+	}
+}
+
+void
+CRubbish::SetVisibility(bool visible)
+{
+	bRubbishInvisible = !visible;
+}
+
+void
+CRubbish::Init(void)
+{
+	int i;
+	for(i = 0; i < NUM_RUBBISH_SHEETS; i++){
+		aSheets[i].m_state = 0;
+		if(i < NUM_RUBBISH_SHEETS-1)
+			aSheets[i].m_next = &aSheets[i+1];
+		else
+			aSheets[i].m_next = &EndEmptyList;
+		if(i > 0)
+			aSheets[i].m_prev = &aSheets[i-1];
+		else
+			aSheets[i].m_prev = &StartEmptyList;
+	}
+
+	StartEmptyList.m_next = &aSheets[0];
+	StartEmptyList.m_prev = nil;
+	EndEmptyList.m_next = nil;
+	EndEmptyList.m_prev = &aSheets[NUM_RUBBISH_SHEETS-1];
+
+	StartStaticsList.m_next = &EndStaticsList;
+	StartStaticsList.m_prev = nil;
+	EndStaticsList.m_next = nil;
+	EndStaticsList.m_prev = &StartStaticsList;
+
+	StartMoversList.m_next = &EndMoversList;
+	StartMoversList.m_prev = nil;
+	EndMoversList.m_next = nil;
+	EndMoversList.m_prev = &StartMoversList;
+
+	// unused
+	RwIm3DVertexSetU(&RubbishVertices[0], 0.0f);
+	RwIm3DVertexSetV(&RubbishVertices[0], 0.0f);
+	RwIm3DVertexSetU(&RubbishVertices[1], 1.0f);
+	RwIm3DVertexSetV(&RubbishVertices[1], 0.0f);
+	RwIm3DVertexSetU(&RubbishVertices[2], 0.0f);
+	RwIm3DVertexSetV(&RubbishVertices[2], 1.0f);
+	RwIm3DVertexSetU(&RubbishVertices[3], 1.0f);
+	RwIm3DVertexSetV(&RubbishVertices[3], 1.0f);
+
+	// unused
+	RubbishIndexList2[0] = 0;
+	RubbishIndexList2[1] = 2;
+	RubbishIndexList2[2] = 1;
+	RubbishIndexList2[3] = 1;
+	RubbishIndexList2[4] = 2;
+	RubbishIndexList2[5] = 3;
+
+	RubbishIndexList[0] = 0;
+	RubbishIndexList[1] = 1;
+	RubbishIndexList[2] = 2;
+	RubbishIndexList[3] = 1;
+	RubbishIndexList[4] = 3;
+	RubbishIndexList[5] = 2;
+
+	CTxdStore::PushCurrentTxd();
+	int slot = CTxdStore::FindTxdSlot("particle");
+	CTxdStore::SetCurrentTxd(slot);
+	gpRubbishTexture[0] = RwTextureRead("gameleaf01_64", nil);
+	gpRubbishTexture[1] = RwTextureRead("gameleaf02_64", nil);
+	gpRubbishTexture[2] = RwTextureRead("newspaper01_64", nil);
+	gpRubbishTexture[3] = RwTextureRead("newspaper02_64", nil);
+	CTxdStore::PopCurrentTxd();
+	RubbishVisibility = 255;
+	bRubbishInvisible = false;
+}
+
+void
+CRubbish::Shutdown(void)
+{
+	RwTextureDestroy(gpRubbishTexture[0]);
+	RwTextureDestroy(gpRubbishTexture[1]);
+	RwTextureDestroy(gpRubbishTexture[2]);
+	RwTextureDestroy(gpRubbishTexture[3]);
+}
diff --git a/src/render/Rubbish.h b/src/render/Rubbish.h
index 17323694..2be592fe 100644
--- a/src/render/Rubbish.h
+++ b/src/render/Rubbish.h
@@ -2,13 +2,50 @@
 
 class CVehicle;
 
+enum {
+	// NB: not all values are allowed, check the code
+	NUM_RUBBISH_SHEETS = 64
+};
+
+class COneSheet
+{
+public:
+	CVector m_basePos;
+	CVector m_animatedPos;
+	float m_targetZ;
+	int8 m_state;
+	int8 m_animationType;
+	uint32 m_moveStart;
+	uint32 m_moveDuration;
+	float m_animHeight;
+	float m_xDist;
+	float m_yDist;
+	float m_angle;
+	bool m_isVisible;
+	bool m_targetIsVisible;
+	COneSheet *m_next;
+	COneSheet *m_prev;
+
+	void AddToList(COneSheet *list);
+	void RemoveFromList(void);
+};
+
 class CRubbish
 {
+	static bool bRubbishInvisible;
+	static int RubbishVisibility;
+	static COneSheet aSheets[NUM_RUBBISH_SHEETS];
+	static COneSheet StartEmptyList;
+	static COneSheet EndEmptyList;
+	static COneSheet StartStaticsList;
+	static COneSheet EndStaticsList;
+	static COneSheet StartMoversList;
+	static COneSheet EndMoversList;
 public:
 	static void Render(void);
 	static void StirUp(CVehicle *veh);	// CAutomobile on PS2
 	static void Update(void);
-	static void SetVisibility(bool);
+	static void SetVisibility(bool visible);
 	static void Init(void);
 	static void Shutdown(void);
 };
diff --git a/src/render/Shadows.h b/src/render/Shadows.h
index 982cc463..fb41ebbc 100644
--- a/src/render/Shadows.h
+++ b/src/render/Shadows.h
@@ -175,11 +175,18 @@ public:
 	static void RenderIndicatorShadow        (uint32 nID, uint8 ShadowType, RwTexture *pTexture,  CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity);
 };
 
-extern RwTexture *&gpBloodPoolTex;
+extern RwTexture *&gpShadowCarTex;
+extern RwTexture *&gpShadowPedTex;
+extern RwTexture *&gpShadowHeliTex;
 extern RwTexture *&gpShadowExplosionTex;
 extern RwTexture *&gpShadowHeadLightsTex;
-extern RwTexture *&gpGoalTex;
 extern RwTexture *&gpOutline1Tex;
 extern RwTexture *&gpOutline2Tex;
 extern RwTexture *&gpOutline3Tex;
+extern RwTexture *&gpBloodPoolTex;
+extern RwTexture *&gpReflectionTex;
+extern RwTexture *&gpGoalMarkerTex;
+extern RwTexture *&gpWalkDontTex;
 extern RwTexture *&gpCrackedGlassTex;
+extern RwTexture *&gpPostShadowTex;
+extern RwTexture *&gpGoalTex;
diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp
index c2725ed6..41ee5d1d 100644
--- a/src/render/Skidmarks.cpp
+++ b/src/render/Skidmarks.cpp
@@ -1,12 +1,247 @@
 #include "common.h"
 #include "patcher.h"
+#include "main.h"
+#include "TxdStore.h"
+#include "Timer.h"
+#include "Replay.h"
 #include "Skidmarks.h"
 
-WRAPPER void CSkidmarks::Clear(void) { EAXJMP(0x518130); }
-WRAPPER void CSkidmarks::Update() { EAXJMP(0x518200); }
+CSkidmark CSkidmarks::aSkidmarks[NUMSKIDMARKS];
 
-WRAPPER void CSkidmarks::Render(void) { EAXJMP(0x5182E0); }
-WRAPPER void CSkidmarks::RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy) { EAXJMP(0x5185C0); }
+RwImVertexIndex SkidmarkIndexList[SKIDMARK_LENGTH * 6];
+RwIm3DVertex SkidmarkVertices[SKIDMARK_LENGTH * 2];
+RwTexture *gpSkidTex;
+RwTexture *gpSkidBloodTex;
+RwTexture *gpSkidMudTex;
 
-WRAPPER void CSkidmarks::Init(void) { EAXJMP(0x517D70); }
-WRAPPER void CSkidmarks::Shutdown(void) { EAXJMP(0x518100); }
+void
+CSkidmarks::Init(void)
+{
+	int i, ix, slot;
+	CTxdStore::PushCurrentTxd();
+	slot = CTxdStore::FindTxdSlot("particle");
+	CTxdStore::SetCurrentTxd(slot);
+	gpSkidTex = RwTextureRead("particleskid", nil);
+	gpSkidBloodTex = RwTextureRead("particleskidblood", nil);
+	gpSkidMudTex = RwTextureRead("particleskidmud", nil);
+	CTxdStore::PopCurrentTxd();
+
+	for(i = 0; i < NUMSKIDMARKS; i++){
+		aSkidmarks[i].m_state = 0;
+		aSkidmarks[i].m_wasUpdated = false;
+	}
+
+	ix = 0;
+	for(i = 0; i < SKIDMARK_LENGTH; i++){
+		SkidmarkIndexList[i*6+0] = ix+0;
+		SkidmarkIndexList[i*6+1] = ix+2;
+		SkidmarkIndexList[i*6+2] = ix+1;
+		SkidmarkIndexList[i*6+3] = ix+1;
+		SkidmarkIndexList[i*6+4] = ix+2;
+		SkidmarkIndexList[i*6+5] = ix+3;
+		ix += 2;
+	}
+
+	for(i = 0; i < SKIDMARK_LENGTH; i++){
+		RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 0], 0.0f);
+		RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 0], i*5.01f);
+		RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 1], 1.0f);
+		RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 1], i*5.01f);
+	}
+}
+
+void
+CSkidmarks::Shutdown(void)
+{
+	RwTextureDestroy(gpSkidTex);
+	RwTextureDestroy(gpSkidBloodTex);
+	RwTextureDestroy(gpSkidMudTex);
+}
+
+void
+CSkidmarks::Clear(void)
+{
+	int i;
+	for(i = 0; i < NUMSKIDMARKS; i++){
+		aSkidmarks[i].m_state = 0;
+		aSkidmarks[i].m_wasUpdated = false;
+	}
+}
+
+void
+CSkidmarks::Update(void)
+{
+	int i;
+	uint32 t1 = CTimer::GetTimeInMilliseconds() + 2500;
+	uint32 t2 = CTimer::GetTimeInMilliseconds() + 5000;
+	uint32 t3 = CTimer::GetTimeInMilliseconds() + 10000;
+	uint32 t4 = CTimer::GetTimeInMilliseconds() + 20000;
+	for(i = 0; i < NUMSKIDMARKS; i++){
+		switch(aSkidmarks[i].m_state){
+		case 1:
+			if(!aSkidmarks[i].m_wasUpdated){
+				// Didn't continue this one last time, so finish it and set fade times
+				aSkidmarks[i].m_state = 2;
+				if(aSkidmarks[i].m_last < 4){
+					aSkidmarks[i].m_fadeStart = t1;
+					aSkidmarks[i].m_fadeEnd = t2;
+				}else if(aSkidmarks[i].m_last < 9){
+					aSkidmarks[i].m_fadeStart = t2;
+					aSkidmarks[i].m_fadeEnd = t3;
+				}else{
+					aSkidmarks[i].m_fadeStart = t3;
+					aSkidmarks[i].m_fadeEnd = t4;
+				}
+			}
+			break;
+		case 2:
+			if(CTimer::GetTimeInMilliseconds() > aSkidmarks[i].m_fadeEnd)
+				aSkidmarks[i].m_state = 0;
+			break;
+		}
+		aSkidmarks[i].m_wasUpdated = false;
+	}
+}
+
+void
+CSkidmarks::Render(void)
+{
+	int i, j;
+	RwTexture *lastTex = nil;
+
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+
+	for(i = 0; i < NUMSKIDMARKS; i++){
+		if(aSkidmarks[i].m_state == 0 || aSkidmarks[i].m_last < 1)
+			continue;
+
+		if(aSkidmarks[i].m_isBloody){
+			if(lastTex != gpSkidBloodTex){
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidBloodTex));
+				lastTex = gpSkidBloodTex;
+			}
+		}else if(aSkidmarks[i].m_isMuddy){
+			if(lastTex != gpSkidMudTex){
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidMudTex));
+				lastTex = gpSkidMudTex;
+			}
+		}else{
+			if(lastTex != gpSkidTex){
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidTex));
+				lastTex = gpSkidTex;
+			}
+		}
+
+		uint32 fade, alpha;
+		if(aSkidmarks[i].m_state == 1 || CTimer::GetTimeInMilliseconds() < aSkidmarks[i].m_fadeStart)
+			fade = 255;
+		else
+			fade = 255*(aSkidmarks[i].m_fadeEnd - CTimer::GetTimeInMilliseconds()) / (aSkidmarks[i].m_fadeEnd - aSkidmarks[i].m_fadeStart);
+
+		for(j = 0; j <= aSkidmarks[i].m_last; j++){
+			alpha = 128;
+			if(j == 0 || j == aSkidmarks[i].m_last && aSkidmarks[i].m_state == 2)
+				alpha = 0;
+			alpha = alpha*fade/256;
+
+			CVector p1 = aSkidmarks[i].m_pos[j] + aSkidmarks[i].m_side[j];
+			CVector p2 = aSkidmarks[i].m_pos[j] - aSkidmarks[i].m_side[j];
+			RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+0], 255, 255, 255, alpha);
+			RwIm3DVertexSetPos(&SkidmarkVertices[j*2+0], p1.x, p1.y, p1.z+0.1f);
+			RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+1], 255, 255, 255, alpha);
+			RwIm3DVertexSetPos(&SkidmarkVertices[j*2+1], p2.x, p2.y, p2.z+0.1f);
+		}
+
+		LittleTest();
+		if(RwIm3DTransform(SkidmarkVertices, 2*(aSkidmarks[i].m_last+1), nil, rwIM3D_VERTEXUV)){
+			RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, SkidmarkIndexList, 6*aSkidmarks[i].m_last);
+			RwIm3DEnd();
+		}
+	}
+
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+}
+
+void
+CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody)
+{
+	int i;
+	CVector2D fwd(fwdX, fwdY);
+
+	if(CReplay::IsPlayingBack())
+		return;
+
+	// Find a skidmark to continue
+	for(i = 0; i < NUMSKIDMARKS; i++)
+		if(aSkidmarks[i].m_state == 1 && aSkidmarks[i].m_id == id)
+			break;
+
+	if(i < NUMSKIDMARKS){
+		// Continue this one
+
+		if(aSkidmarks[i].m_isBloody != *isBloody){
+			// Blood-status changed, end this one
+			aSkidmarks[i].m_state = 2;
+			aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
+			aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
+			return;
+		}
+
+		aSkidmarks[i].m_wasUpdated = true;
+
+		if(CTimer::GetTimeInMilliseconds() - aSkidmarks[i].m_lastUpdate <= 100){
+			// Last update was recently, just change last coords
+			aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
+			return;
+		}
+		aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds();
+
+		if(aSkidmarks[i].m_last >= SKIDMARK_LENGTH-1){
+			// No space to continue, end it
+			aSkidmarks[i].m_state = 2;
+			aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
+			aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
+			*isBloody = false;	// stpo blood marks at end
+			return;
+		}
+		aSkidmarks[i].m_last++;
+
+		aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
+
+		CVector2D dist = aSkidmarks[i].m_pos[aSkidmarks[i].m_last] - aSkidmarks[i].m_pos[aSkidmarks[i].m_last-1];
+		dist.Normalise();
+		CVector2D right(dist.y, -dist.x);
+		float turn = DotProduct2D(fwd, right);
+		turn = Abs(turn) + 1.0f;
+		aSkidmarks[i].m_side[aSkidmarks[i].m_last] = CVector(right.x, right.y, 0.0f) * turn * 0.125f;
+		if(aSkidmarks[i].m_last == 1)
+			aSkidmarks[i].m_side[0] = aSkidmarks[i].m_side[1];
+
+		if(aSkidmarks[i].m_last > 8)
+			*isBloody = false;	// stop blood marks after 8
+		return;
+	}
+
+	// Start a new one
+	for(i = 0; i < NUMSKIDMARKS; i++)
+		if(aSkidmarks[i].m_state == 0)
+			break;
+	if(i < NUMSKIDMARKS){
+		// Found a free slot
+		aSkidmarks[i].m_state = 1;
+		aSkidmarks[i].m_id = id;
+		aSkidmarks[i].m_pos[0] = pos;
+		aSkidmarks[i].m_side[0] = CVector(0.0f, 0.0f, 0.0f);
+		aSkidmarks[i].m_wasUpdated = true;
+		aSkidmarks[i].m_last = 0;
+		aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds() - 1000;
+		aSkidmarks[i].m_isBloody = *isBloody;
+		aSkidmarks[i].m_isMuddy = *isMuddy;
+	}else
+		*isBloody = false;	// stop blood marks if no space
+}
diff --git a/src/render/Skidmarks.h b/src/render/Skidmarks.h
index bf2da7e4..085b4c6d 100644
--- a/src/render/Skidmarks.h
+++ b/src/render/Skidmarks.h
@@ -1,12 +1,32 @@
 #pragma once
 
+enum { SKIDMARK_LENGTH = 16 };
+
+class CSkidmark
+{
+public:
+	uint8 m_state;
+	bool m_wasUpdated;
+	bool m_isBloody;
+	bool m_isMuddy;
+	uintptr m_id;
+	int16 m_last;
+	uint32 m_lastUpdate;;
+	uint32 m_fadeStart;
+	uint32 m_fadeEnd;
+	CVector m_pos[SKIDMARK_LENGTH];
+	CVector m_side[SKIDMARK_LENGTH];
+};
+
 class CSkidmarks
 {
+	static CSkidmark aSkidmarks[NUMSKIDMARKS];
 public:
+
+	static void Init(void);
+	static void Shutdown(void);
 	static void Clear(void);
 	static void Update(void);
 	static void Render(void);
-	static void RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy);
-	static void Init(void);
-	static void Shutdown(void);
+	static void RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody);
 };
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 301ae265..9189a7c2 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -1,6 +1,7 @@
 #include "common.h"
 #include "patcher.h"
 #include "SpecialFX.h"
+#include "RenderBuffer.h"
 #include "Timer.h"
 #include "Sprite.h"
 #include "Font.h"
@@ -8,26 +9,260 @@
 #include "TxdStore.h"
 #include "FileMgr.h"
 #include "FileLoader.h"
+#include "Timecycle.h"
 #include "Lights.h"
+#include "ModelIndices.h"
 #include "VisibilityPlugins.h"
 #include "World.h"
+#include "PlayerPed.h"
 #include "Particle.h"
+#include "Shadows.h"
 #include "General.h"
 #include "Camera.h"
 #include "Shadows.h"
 #include "main.h"
 
-WRAPPER void CSpecialFX::Render(void) { EAXJMP(0x518DC0); }
-WRAPPER void CSpecialFX::Update(void) { EAXJMP(0x518D40); }
-WRAPPER void CSpecialFX::Init(void) { EAXJMP(0x5189E0); }
-WRAPPER void CSpecialFX::Shutdown(void) { EAXJMP(0x518BE0); }
+RwIm3DVertex StreakVertices[4];
+RwImVertexIndex StreakIndexList[12];
 
-WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2) { EAXJMP(0x519460); }
+RwIm3DVertex TraceVertices[6];
+RwImVertexIndex TraceIndexList[12];
 
 
-CBulletTrace (&CBulletTraces::aTraces)[NUMBULLETTRACES] = *(CBulletTrace(*)[NUMBULLETTRACES])*(uintptr*)0x72B1B8;
-RxObjSpace3DVertex (&TraceVertices)[6] = *(RxObjSpace3DVertex(*)[6])*(uintptr*)0x649884;
-RwImVertexIndex (&TraceIndexList)[12] = *(RwImVertexIndex(*)[12])*(uintptr*)0x64986C;
+void
+CSpecialFX::Init(void)
+{
+	CBulletTraces::Init();
+
+	RwIm3DVertexSetU(&StreakVertices[0], 0.0f);
+	RwIm3DVertexSetV(&StreakVertices[0], 0.0f);
+	RwIm3DVertexSetU(&StreakVertices[1], 1.0f);
+	RwIm3DVertexSetV(&StreakVertices[1], 0.0f);
+	RwIm3DVertexSetU(&StreakVertices[2], 0.0f);
+	RwIm3DVertexSetV(&StreakVertices[2], 0.0f);
+	RwIm3DVertexSetU(&StreakVertices[3], 1.0f);
+	RwIm3DVertexSetV(&StreakVertices[3], 0.0f);
+
+	StreakIndexList[0] = 0;
+	StreakIndexList[1] = 1;
+	StreakIndexList[2] = 2;
+	StreakIndexList[3] = 1;
+	StreakIndexList[4] = 3;
+	StreakIndexList[5] = 2;
+	StreakIndexList[6] = 0;
+	StreakIndexList[7] = 2;
+	StreakIndexList[8] = 1;
+	StreakIndexList[9] = 1;
+	StreakIndexList[10] = 2;
+	StreakIndexList[11] = 3;
+
+	RwIm3DVertexSetRGBA(&TraceVertices[0], 20, 20, 20, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[1], 20, 20, 20, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[2], 70, 70, 70, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[3], 70, 70, 70, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[4], 10, 10, 10, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[5], 10, 10, 10, 255);
+	RwIm3DVertexSetU(&TraceVertices[0], 0.0);
+	RwIm3DVertexSetV(&TraceVertices[0], 0.0);
+	RwIm3DVertexSetU(&TraceVertices[1], 1.0);
+	RwIm3DVertexSetV(&TraceVertices[1], 0.0);
+	RwIm3DVertexSetU(&TraceVertices[2], 0.0);
+	RwIm3DVertexSetV(&TraceVertices[2], 0.5);
+	RwIm3DVertexSetU(&TraceVertices[3], 1.0);
+	RwIm3DVertexSetV(&TraceVertices[3], 0.5);
+	RwIm3DVertexSetU(&TraceVertices[4], 0.0);
+	RwIm3DVertexSetV(&TraceVertices[4], 1.0);
+	RwIm3DVertexSetU(&TraceVertices[5], 1.0);
+	RwIm3DVertexSetV(&TraceVertices[5], 1.0);
+
+	TraceIndexList[0] = 0;
+	TraceIndexList[1] = 2;
+	TraceIndexList[2] = 1;
+	TraceIndexList[3] = 1;
+	TraceIndexList[4] = 2;
+	TraceIndexList[5] = 3;
+	TraceIndexList[6] = 2;
+	TraceIndexList[7] = 4;
+	TraceIndexList[8] = 3;
+	TraceIndexList[9] = 3;
+	TraceIndexList[10] = 4;
+	TraceIndexList[11] = 5;
+
+	CMotionBlurStreaks::Init();
+	CBrightLights::Init();
+	CShinyTexts::Init();
+	CMoneyMessages::Init();
+	C3dMarkers::Init();
+}
+
+RwObject*
+LookForBatCB(RwObject *object, void *data)
+{
+	static CMatrix MatLTM;
+
+	if(CVisibilityPlugins::GetAtomicModelInfo((RpAtomic*)object) == (CSimpleModelInfo*)data){
+		MatLTM = CMatrix(RwFrameGetLTM(RpAtomicGetFrame((RpAtomic*)object)));
+		CVector p1 = MatLTM * CVector(0.02f, 0.05f, 0.07f);
+		CVector p2 = MatLTM * CVector(0.246f, 0.0325f, 0.796f);
+		CMotionBlurStreaks::RegisterStreak((uintptr)object, 100, 100, 100, p1, p2);
+	}
+	return nil;
+}
+
+void
+CSpecialFX::Update(void)
+{
+	CMotionBlurStreaks::Update();
+	CBulletTraces::Update();
+
+	if(FindPlayerPed() &&
+	   FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT &&
+	   FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING)
+		RwFrameForAllObjects(FindPlayerPed()->GetNodeFrame(PED_HANDR), LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
+}
+
+void
+CSpecialFX::Shutdown(void)
+{
+	C3dMarkers::Shutdown();
+}
+
+void
+CSpecialFX::Render(void)
+{
+	CMotionBlurStreaks::Render();
+	CBulletTraces::Render();
+	CBrightLights::Render();
+	CShinyTexts::Render();
+	CMoneyMessages::Render();
+	C3dMarkers::Render();
+}
+
+CRegisteredMotionBlurStreak CMotionBlurStreaks::aStreaks[NUMMBLURSTREAKS];
+
+void
+CRegisteredMotionBlurStreak::Update(void)
+{
+	int i;
+	bool wasUpdated;
+	bool lastWasUpdated = false;
+	for(i = 2; i > 0; i--){
+		m_pos1[i] = m_pos1[i-1];
+		m_pos2[i] = m_pos2[i-1];
+		m_isValid[i] = m_isValid[i-1];
+		wasUpdated = true;
+		if(!lastWasUpdated && !m_isValid[i])
+			wasUpdated = false;
+		lastWasUpdated = wasUpdated;
+	}
+	m_isValid[0] = false;
+	if(!wasUpdated)
+		m_id = 0;
+}
+
+void
+CRegisteredMotionBlurStreak::Render(void)
+{
+	int i;
+	int a1, a2;
+	for(i = 0; i < 2; i++)
+		if(m_isValid[i] && m_isValid[i+1]){
+			a1 = (255/3)*(3-i)/3;
+			RwIm3DVertexSetRGBA(&StreakVertices[0], m_red, m_green, m_blue, a1);
+			RwIm3DVertexSetRGBA(&StreakVertices[1], m_red, m_green, m_blue, a1);
+			a2 = (255/3)*(3-(i+1))/3;
+			RwIm3DVertexSetRGBA(&StreakVertices[2], m_red, m_green, m_blue, a2);
+			RwIm3DVertexSetRGBA(&StreakVertices[3], m_red, m_green, m_blue, a2);
+			RwIm3DVertexSetPos(&StreakVertices[0], m_pos1[i].x, m_pos1[i].y, m_pos1[i].z);
+			RwIm3DVertexSetPos(&StreakVertices[1], m_pos2[i].x, m_pos2[i].y, m_pos2[i].z);
+			RwIm3DVertexSetPos(&StreakVertices[2], m_pos1[i+1].x, m_pos1[i+1].y, m_pos1[i+1].z);
+			RwIm3DVertexSetPos(&StreakVertices[3], m_pos2[i+1].x, m_pos2[i+1].y, m_pos2[i+1].z);
+			LittleTest();
+			if(RwIm3DTransform(StreakVertices, 4, nil, rwIM3D_VERTEXUV)){
+				RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, StreakIndexList, 12);
+				RwIm3DEnd();
+			}
+		}
+}
+
+void
+CMotionBlurStreaks::Init(void)
+{
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++)
+		aStreaks[i].m_id = 0;
+}
+
+void
+CMotionBlurStreaks::Update(void)
+{
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++)
+		if(aStreaks[i].m_id)
+			aStreaks[i].Update();
+}
+
+void
+CMotionBlurStreaks::RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2)
+{
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++){
+		if(aStreaks[i].m_id == id){
+			// Found a streak from last frame, update
+			aStreaks[i].m_red = r;
+			aStreaks[i].m_green = g;
+			aStreaks[i].m_blue = b;
+			aStreaks[i].m_pos1[0] = p1;
+			aStreaks[i].m_pos2[0] = p2;
+			aStreaks[i].m_isValid[0] = true;
+			return;
+		}
+	}
+	// Find free slot
+	for(i = 0; aStreaks[i].m_id; i++)
+		if(i == NUMMBLURSTREAKS-1)
+			return;
+	// Create a new streak
+	aStreaks[i].m_id = id;
+	aStreaks[i].m_red = r;
+	aStreaks[i].m_green = g;
+	aStreaks[i].m_blue = b;
+	aStreaks[i].m_pos1[0] = p1;
+	aStreaks[i].m_pos2[0] = p2;
+	aStreaks[i].m_isValid[0] = true;
+	aStreaks[i].m_isValid[1] = false;
+	aStreaks[i].m_isValid[2] = false;
+}
+
+void
+CMotionBlurStreaks::Render(void)
+{
+	bool setRenderStates = false;
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++)
+		if(aStreaks[i].m_id){
+			if(!setRenderStates){
+				RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+				RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+				RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
+				RwRenderStateSet(rwRENDERSTATEFOGCOLOR,
+					(void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
+				RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+				RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
+ 				setRenderStates = true;
+			}
+			aStreaks[i].Render();
+		}
+	if(setRenderStates){
+		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
+	}
+}
+
+
+CBulletTrace CBulletTraces::aTraces[NUMBULLETTRACES];
 
 void CBulletTraces::Init(void)
 {
@@ -56,10 +291,10 @@ void CBulletTraces::Render(void)
 	for (int i = 0; i < NUMBULLETTRACES; i++) {
 		if (!aTraces[i].m_bInUse)
 			continue;
-		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)0);
-		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)2);
-		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)2);
-		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpShadowExplosionTex->raster);
+		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpShadowExplosionTex));
 		CVector inf = aTraces[i].m_vecCurrentPos;
 		CVector sup = aTraces[i].m_vecTargetPos;
 		CVector center = (inf + sup) / 2;
@@ -81,9 +316,9 @@ void CBulletTraces::Render(void)
 			RwIm3DEnd();
 		}
 	}
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1);
-	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)5);
-	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)6);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
 }
 
 void CBulletTraces::Update(void)
@@ -115,8 +350,6 @@ void CBulletTrace::Update(void)
 	m_framesInUse++;
 }
 
-WRAPPER void CBrightLights::RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1, uint8 unk2, uint8 unk3) { EAXJMP(0x51A410); }
-
 RpAtomic *
 MarkerAtomicCB(RpAtomic *atomic, void *data)
 {
@@ -181,8 +414,7 @@ C3dMarker::Render()
 {
 	if (m_pAtomic == nil) return;
 
-	RwRGBA *color = RpMaterialGetColor(m_pMaterial);
-	*color = m_Color;
+	RpMaterialSetColor(m_pMaterial, &m_Color);
 
 	m_Matrix.UpdateRW();
 
@@ -201,9 +433,9 @@ C3dMarker::Render()
 	ReSetAmbientAndDirectionalColours();
 }
 
-C3dMarker(&C3dMarkers::m_aMarkerArray)[NUM3DMARKERS] = *(C3dMarker(*)[NUM3DMARKERS])*(uintptr*)0x72D408;
-int32 &C3dMarkers::NumActiveMarkers = *(int32*)0x8F2A08;
-RpClump* (&C3dMarkers::m_pRpClumpArray)[NUMMARKERTYPES] = *(RpClump*(*)[NUMMARKERTYPES])*(uintptr*)0x8E2888;
+C3dMarker C3dMarkers::m_aMarkerArray[NUM3DMARKERS];
+int32 C3dMarkers::NumActiveMarkers;
+RpClump* C3dMarkers::m_pRpClumpArray[NUMMARKERTYPES];
 
 void
 C3dMarkers::Init()
@@ -402,6 +634,377 @@ C3dMarkers::Update()
 {
 }
 
+
+#define BRIGHTLIGHTS_MAX_DIST (60.0f)	// invisible beyond this
+#define BRIGHTLIGHTS_FADE_DIST (45.0f)	// strongest between these two
+#define CARLIGHTS_MAX_DIST (30.0f)
+#define CARLIGHTS_FADE_DIST (15.0f)	// 31 for close lights
+
+int CBrightLights::NumBrightLights;
+CBrightLight CBrightLights::aBrightLights[NUMBRIGHTLIGHTS];
+
+void
+CBrightLights::Init(void)
+{
+	NumBrightLights = 0;
+}
+
+void
+CBrightLights::RegisterOne(CVector pos, CVector up, CVector side, CVector front,
+	uint8 type, uint8 red, uint8 green, uint8 blue)
+{
+	if(NumBrightLights >= NUMBRIGHTLIGHTS)
+		return;
+
+	aBrightLights[NumBrightLights].m_camDist = (pos - TheCamera.GetPosition()).Magnitude();
+	if(aBrightLights[NumBrightLights].m_camDist > BRIGHTLIGHTS_MAX_DIST)
+		return;
+
+	aBrightLights[NumBrightLights].m_pos = pos;
+	aBrightLights[NumBrightLights].m_up = up;
+	aBrightLights[NumBrightLights].m_side = side;
+	aBrightLights[NumBrightLights].m_front = front;
+	aBrightLights[NumBrightLights].m_type = type;
+	aBrightLights[NumBrightLights].m_red = red;
+	aBrightLights[NumBrightLights].m_green = green;
+	aBrightLights[NumBrightLights].m_blue = blue;
+
+	NumBrightLights++;
+}
+
+static float TrafficLightsSide[6] = { -0.09f, 0.09f, 0.162f, 0.09f, -0.09f, -0.162f };
+static float TrafficLightsUp[6] = { 0.162f, 0.162f, 0.0f, -0.162f, -0.162f, 0.0f };
+static float LongCarHeadLightsSide[8] = { -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f };
+static float LongCarHeadLightsFront[8] = { 0.1f, 0.1f, -0.1f, -0.1f, 0.1f, 0.1f, -0.1f, -0.1f };
+static float LongCarHeadLightsUp[8] = { 0.1f, 0.1f, 0.1f, 0.1f, -0.1f, -0.1f, -0.1f, -0.1f };
+static float SmallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
+static float SmallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
+static float SmallCarHeadLightsUp[8] = { 0.08f, 0.08f, 0.08f, 0.08f, -0.08f, -0.08f, -0.08f, -0.08f };
+static float BigCarHeadLightsSide[8] = { -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f };
+static float BigCarHeadLightsFront[8] = { 0.15f, 0.15f, -0.15f, -0.15f, 0.15f, 0.15f, -0.15f, -0.15f };
+static float BigCarHeadLightsUp[8] = { 0.15f, 0.15f, 0.15f, 0.15f, -0.15f, -0.15f, -0.15f, -0.15f };
+static float TallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
+static float TallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
+static float TallCarHeadLightsUp[8] = { 0.2f, 0.2f, 0.2f, 0.2f, -0.2f, -0.2f, -0.2f, -0.2f };
+static float SirenLightsSide[6] = { -0.04f, 0.04f, 0.06f, 0.04f, -0.04f, -0.06f };
+static float SirenLightsUp[6] = { 0.06f, 0.06f, 0.0f, -0.06f, -0.06f, 0.0f };
+static RwImVertexIndex TrafficLightIndices[4*3] = { 0, 1, 5,  1, 2, 3,  1, 3, 4,  1, 4, 5 };
+static RwImVertexIndex CubeIndices[12*3] = {
+	0, 2, 1,  1, 2, 3,  3, 5, 1,  3, 7, 5,
+	2, 7, 3,  2, 6, 7,  4, 0, 1,  4, 1, 5,
+	6, 0, 4,  6, 2, 0,  6, 5, 7,  6, 4, 5
+};
+
+void
+CBrightLights::Render(void)
+{
+	int i, j;
+	CVector pos;
+
+	if(NumBrightLights == 0)
+		return;
+
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+
+	for(i = 0; i < NumBrightLights; i++){
+		if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-40 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-40)
+			RenderOutGeometryBuffer();
+
+		int r, g, b, a;
+		float flicker = (CGeneral::GetRandomNumber()&0xFF) * 0.2f;
+		switch(aBrightLights[i].m_type){
+		case BRIGHTLIGHT_TRAFFIC_GREEN:
+			r = flicker; g = 255; b = flicker;
+			break;
+		case BRIGHTLIGHT_TRAFFIC_YELLOW:
+			r = 255; g = 128; b = flicker;
+			break;
+		case BRIGHTLIGHT_TRAFFIC_RED:
+			r = 255; g = flicker; b = flicker;
+			break;
+
+		case BRIGHTLIGHT_FRONT_LONG:
+		case BRIGHTLIGHT_FRONT_SMALL:
+		case BRIGHTLIGHT_FRONT_BIG:
+		case BRIGHTLIGHT_FRONT_TALL:
+			r = 255; g = 255; b = 255;
+			break;
+
+		case BRIGHTLIGHT_REAR_LONG:
+		case BRIGHTLIGHT_REAR_SMALL:
+		case BRIGHTLIGHT_REAR_BIG:
+		case BRIGHTLIGHT_REAR_TALL:
+			r = 255; g = flicker; b = flicker;
+			break;
+
+		case BRIGHTLIGHT_SIREN:
+			r = aBrightLights[i].m_red;
+			g = aBrightLights[i].m_green;
+			b = aBrightLights[i].m_blue;
+			break;
+		}
+
+		if(aBrightLights[i].m_camDist < BRIGHTLIGHTS_FADE_DIST)
+			a = 255;
+		else
+			a = 255*(1.0f - (aBrightLights[i].m_camDist-BRIGHTLIGHTS_FADE_DIST)/(BRIGHTLIGHTS_MAX_DIST-BRIGHTLIGHTS_FADE_DIST));
+		// fade car lights down to 31 as they come near
+		if(aBrightLights[i].m_type >= BRIGHTLIGHT_FRONT_LONG && aBrightLights[i].m_type <= BRIGHTLIGHT_REAR_TALL){
+			if(aBrightLights[i].m_camDist < CARLIGHTS_FADE_DIST)
+				a = 31;
+			else if(aBrightLights[i].m_camDist < CARLIGHTS_MAX_DIST)
+				a = 31 + (255-31)*((aBrightLights[i].m_camDist-CARLIGHTS_FADE_DIST)/(CARLIGHTS_MAX_DIST-CARLIGHTS_FADE_DIST));
+		}
+
+		switch(aBrightLights[i].m_type){
+		case BRIGHTLIGHT_TRAFFIC_GREEN:
+		case BRIGHTLIGHT_TRAFFIC_YELLOW:
+		case BRIGHTLIGHT_TRAFFIC_RED:
+			for(j = 0; j < 6; j++){
+				pos = TrafficLightsSide[j]*aBrightLights[i].m_side +
+					TrafficLightsUp[j]*aBrightLights[i].m_up +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 4*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 6;
+			TempBufferIndicesStored += 4*3;
+			break;
+
+		case BRIGHTLIGHT_FRONT_LONG:
+		case BRIGHTLIGHT_REAR_LONG:
+			for(j = 0; j < 8; j++){
+				pos = LongCarHeadLightsSide[j]*aBrightLights[i].m_side +
+					LongCarHeadLightsUp[j]*aBrightLights[i].m_up +
+					LongCarHeadLightsFront[j]*aBrightLights[i].m_front +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 12*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 8;
+			TempBufferIndicesStored += 12*3;
+			break;
+
+		case BRIGHTLIGHT_FRONT_SMALL:
+		case BRIGHTLIGHT_REAR_SMALL:
+			for(j = 0; j < 8; j++){
+				pos = SmallCarHeadLightsSide[j]*aBrightLights[i].m_side +
+					SmallCarHeadLightsUp[j]*aBrightLights[i].m_up +
+					SmallCarHeadLightsFront[j]*aBrightLights[i].m_front +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 12*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 8;
+			TempBufferIndicesStored += 12*3;
+			break;
+
+		case BRIGHTLIGHT_FRONT_TALL:
+		case BRIGHTLIGHT_REAR_TALL:
+			for(j = 0; j < 8; j++){
+				pos = TallCarHeadLightsSide[j]*aBrightLights[i].m_side +
+					TallCarHeadLightsUp[j]*aBrightLights[i].m_up +
+					TallCarHeadLightsFront[j]*aBrightLights[i].m_front +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 12*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 8;
+			TempBufferIndicesStored += 12*3;
+			break;
+
+		case BRIGHTLIGHT_SIREN:
+			for(j = 0; j < 6; j++){
+				pos = SirenLightsSide[j]*aBrightLights[i].m_side +
+					SirenLightsUp[j]*aBrightLights[i].m_up +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 4*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 6;
+			TempBufferIndicesStored += 4*3;
+			break;
+
+		}
+	}
+
+	RenderOutGeometryBuffer();
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	NumBrightLights = 0;
+}
+
+void
+CBrightLights::RenderOutGeometryBuffer(void)
+{
+	if(TempBufferIndicesStored != 0){
+		LittleTest();
+		if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+			RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+			RwIm3DEnd();
+		}
+		TempBufferVerticesStored = 0;
+		TempBufferIndicesStored = 0;
+	}
+}
+
+int CShinyTexts::NumShinyTexts;
+CShinyText CShinyTexts::aShinyTexts[NUMSHINYTEXTS];
+
+void
+CShinyTexts::Init(void)
+{
+	NumShinyTexts = 0;
+}
+
+void
+CShinyTexts::RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
+	float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
+	uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist)
+{
+	if(NumShinyTexts >= NUMSHINYTEXTS)
+		return;
+
+	aShinyTexts[NumShinyTexts].m_camDist = (p0 - TheCamera.GetPosition()).Magnitude();
+	if(aShinyTexts[NumShinyTexts].m_camDist > maxDist)
+		return;
+	aShinyTexts[NumShinyTexts].m_verts[0] = p0;
+	aShinyTexts[NumShinyTexts].m_verts[1] = p1;
+	aShinyTexts[NumShinyTexts].m_verts[2] = p2;
+	aShinyTexts[NumShinyTexts].m_verts[3] = p3;
+	aShinyTexts[NumShinyTexts].m_texCoords[0].x = u0;
+	aShinyTexts[NumShinyTexts].m_texCoords[0].y = v0;
+	aShinyTexts[NumShinyTexts].m_texCoords[1].x = u1;
+	aShinyTexts[NumShinyTexts].m_texCoords[1].y = v1;
+	aShinyTexts[NumShinyTexts].m_texCoords[2].x = u2;
+	aShinyTexts[NumShinyTexts].m_texCoords[2].y = v2;
+	aShinyTexts[NumShinyTexts].m_texCoords[3].x = u3;
+	aShinyTexts[NumShinyTexts].m_texCoords[3].y = v3;
+	aShinyTexts[NumShinyTexts].m_type = type;
+	aShinyTexts[NumShinyTexts].m_red = red;
+	aShinyTexts[NumShinyTexts].m_green = green;
+	aShinyTexts[NumShinyTexts].m_blue = blue;
+	// Fade out at half the max dist
+	float halfDist = maxDist*0.5f;
+	if(aShinyTexts[NumShinyTexts].m_camDist > halfDist){
+		float f = 1.0f - (aShinyTexts[NumShinyTexts].m_camDist - halfDist)/halfDist;
+		aShinyTexts[NumShinyTexts].m_red *= f;
+		aShinyTexts[NumShinyTexts].m_green *= f;
+		aShinyTexts[NumShinyTexts].m_blue *= f;
+	}
+
+	NumShinyTexts++;
+}
+
+void
+CShinyTexts::Render(void)
+{
+	int i, ix, v;
+	RwTexture *lastTex = nil;
+
+	if(NumShinyTexts == 0)
+		return;
+
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+
+	TempBufferVerticesStored = 0;
+	TempBufferIndicesStored = 0;
+
+	for(i = 0; i < NumShinyTexts; i++){
+		if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-64 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-62)
+			RenderOutGeometryBuffer();
+
+		uint8 r = aShinyTexts[i].m_red;
+		uint8 g = aShinyTexts[i].m_green;
+		uint8 b = aShinyTexts[i].m_blue;
+
+		switch(aShinyTexts[i].m_type){
+		case SHINYTEXT_WALK:
+			if(lastTex != gpWalkDontTex){
+				RenderOutGeometryBuffer();
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpWalkDontTex));
+				lastTex = gpWalkDontTex;
+			}
+	quad:
+			v = TempBufferVerticesStored;
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_verts[0].x, aShinyTexts[i].m_verts[0].y, aShinyTexts[i].m_verts[0].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].y);
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_verts[1].x, aShinyTexts[i].m_verts[1].y, aShinyTexts[i].m_verts[1].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].y);
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_verts[2].x, aShinyTexts[i].m_verts[2].y, aShinyTexts[i].m_verts[2].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].y);
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_verts[3].x, aShinyTexts[i].m_verts[3].y, aShinyTexts[i].m_verts[3].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].y);
+			ix = TempBufferIndicesStored;
+			TempBufferRenderIndexList[ix+0] = 0 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+1] = 1 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+2] = 2 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+3] = 2 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+4] = 1 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+5] = 3 + TempBufferVerticesStored;
+			TempBufferVerticesStored += 4;
+			TempBufferIndicesStored += 6;
+			break;
+
+		case SHINYTEXT_FLAT:
+			if(lastTex != nil){
+				RenderOutGeometryBuffer();
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+				lastTex = nil;
+			}
+			goto quad;
+		}
+	}
+
+	RenderOutGeometryBuffer();
+	NumShinyTexts = 0;
+
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+}
+
+void
+CShinyTexts::RenderOutGeometryBuffer(void)
+{
+	if(TempBufferIndicesStored != 0){
+		LittleTest();
+		if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+			RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+			RwIm3DEnd();
+		}
+		TempBufferVerticesStored = 0;
+		TempBufferIndicesStored = 0;
+	}
+}
+
+
+
 #define MONEY_MESSAGE_LIFETIME_MS 2000
 
 CMoneyMessage CMoneyMessages::aMoneyMessages[NUMMONEYMESSAGES];
@@ -564,6 +1167,16 @@ STARTPATCHES
 	InjectHook(0x51B400, C3dMarkers::Render, PATCH_JUMP);
 	InjectHook(0x51B3B0, C3dMarkers::Shutdown, PATCH_JUMP);
 	
+	InjectHook(0x5197A0, CBrightLights::Init, PATCH_JUMP);
+	InjectHook(0x51A410, CBrightLights::RegisterOne, PATCH_JUMP);
+	InjectHook(0x5197B0, CBrightLights::Render, PATCH_JUMP);
+	InjectHook(0x51A3B0, CBrightLights::RenderOutGeometryBuffer, PATCH_JUMP);
+
+	InjectHook(0x51A5A0, CShinyTexts::Init, PATCH_JUMP);
+	InjectHook(0x51AAB0, CShinyTexts::RegisterOne, PATCH_JUMP);
+	InjectHook(0x51A5B0, CShinyTexts::Render, PATCH_JUMP);
+	InjectHook(0x51AA50, CShinyTexts::RenderOutGeometryBuffer, PATCH_JUMP);
+
 	InjectHook(0x51AF70, CMoneyMessages::Init, PATCH_JUMP);
 	InjectHook(0x51B030, CMoneyMessages::Render, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index fc155a53..2d9f18b1 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -9,10 +9,29 @@ public:
 	static void Shutdown(void);
 };
 
-class CMotionBlurStreaks
+class CRegisteredMotionBlurStreak
 {
 public:
-	static void RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
+	uintptr m_id;
+	uint8 m_red;
+	uint8 m_green;
+	uint8 m_blue;
+	CVector m_pos1[3];
+	CVector m_pos2[3];
+	bool m_isValid[3];
+
+	void Update(void);
+	void Render(void);
+};
+
+class CMotionBlurStreaks
+{
+	static CRegisteredMotionBlurStreak aStreaks[NUMMBLURSTREAKS];
+public:
+	static void Init(void);
+	static void Update(void);
+	static void RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
+	static void Render(void);
 };
 
 struct CBulletTrace
@@ -29,7 +48,7 @@ struct CBulletTrace
 class CBulletTraces
 {
 public:
-	static CBulletTrace (&aTraces)[NUMBULLETTRACES];
+	static CBulletTrace aTraces[NUMBULLETTRACES];
 
 	static void Init(void);
 	static void AddTrace(CVector*, CVector*);
@@ -37,12 +56,6 @@ public:
 	static void Update(void);
 };
 
-class CBrightLights
-{
-public:
-	static void RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1 = 0, uint8 unk2 = 0, uint8 unk3 = 0);
-};
-
 enum
 {
 	MARKERTYPE_0 = 0,
@@ -57,27 +70,27 @@ enum
 
 
 class C3dMarker
-{
-public:
-	CMatrix m_Matrix;
-	RpAtomic *m_pAtomic;
-	RpMaterial *m_pMaterial;
-	uint16 m_nType;
-	bool m_bIsUsed;
-	uint32 m_nIdentifier;
-	RwRGBA m_Color;
-	uint16 m_nPulsePeriod;
-	int16 m_nRotateRate;
-	uint32 m_nStartTime;
-	float m_fPulseFraction;
-	float m_fStdSize;
-	float m_fSize;
-	float m_fBrightness;
-	float m_fCameraRange;
-
-	bool AddMarker(uint32 identifier, uint16 type, float fSize, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
-	void DeleteMarkerObject();
-	void Render();
+{
+public:
+	CMatrix m_Matrix;
+	RpAtomic *m_pAtomic;
+	RpMaterial *m_pMaterial;
+	uint16 m_nType;
+	bool m_bIsUsed;
+	uint32 m_nIdentifier;
+	RwRGBA m_Color;
+	uint16 m_nPulsePeriod;
+	int16 m_nRotateRate;
+	uint32 m_nStartTime;
+	float m_fPulseFraction;
+	float m_fStdSize;
+	float m_fSize;
+	float m_fBrightness;
+	float m_fCameraRange;
+
+	bool AddMarker(uint32 identifier, uint16 type, float fSize, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
+	void DeleteMarkerObject();
+	void Render();
 };
 
 class C3dMarkers
@@ -87,42 +100,125 @@ public:
 	static void Shutdown();
 	static C3dMarker *PlaceMarker(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
 	static void PlaceMarkerSet(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
-	static void Render();
+	static void Render();
 	static void Update();
 
-	static C3dMarker(&m_aMarkerArray)[NUM3DMARKERS];
-	static int32 &NumActiveMarkers;
-	static RpClump* (&m_pRpClumpArray)[NUMMARKERTYPES];
-};
-
-class CMoneyMessage
-{
-	friend class CMoneyMessages;
-
-	uint32	m_nTimeRegistered;
-	CVector	m_vecPosition;
-	wchar	m_aText[16];
-	CRGBA	m_Colour;
-	float	m_fSize;
-	float	m_fOpacity;
-public:
-	void Render();
-};
-
-class CMoneyMessages
-{
-	static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
-public:
-	static void Init();
-	static void Render();
-	static void	RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity);
-};
-
-class CSpecialParticleStuff
-{
-	static uint32 BoatFromStart;
-public:
-	static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
-	static void StartBoatFoamAnimation();
-	static void UpdateBoatFoamAnimation(CMatrix*);
-};
+	static C3dMarker m_aMarkerArray[NUM3DMARKERS];
+	static int32 NumActiveMarkers;
+	static RpClump* m_pRpClumpArray[NUMMARKERTYPES];
+};
+
+enum
+{
+	BRIGHTLIGHT_INVALID,
+	BRIGHTLIGHT_TRAFFIC_GREEN,
+	BRIGHTLIGHT_TRAFFIC_YELLOW,
+	BRIGHTLIGHT_TRAFFIC_RED,
+
+	// white
+	BRIGHTLIGHT_FRONT_LONG,
+	BRIGHTLIGHT_FRONT_SMALL,
+	BRIGHTLIGHT_FRONT_BIG,
+	BRIGHTLIGHT_FRONT_TALL,
+
+	// red
+	BRIGHTLIGHT_REAR_LONG,
+	BRIGHTLIGHT_REAR_SMALL,
+	BRIGHTLIGHT_REAR_BIG,
+	BRIGHTLIGHT_REAR_TALL,
+
+	BRIGHTLIGHT_SIREN,	// unused
+
+	BRIGHTLIGHT_FRONT = BRIGHTLIGHT_FRONT_LONG,
+	BRIGHTLIGHT_REAR = BRIGHTLIGHT_REAR_LONG,
+};
+
+class CBrightLight
+{
+public:
+	CVector m_pos;
+	CVector m_up;
+	CVector m_side;
+	CVector m_front;
+	float m_camDist;
+	uint8 m_type;
+	uint8 m_red;
+	uint8 m_green;
+	uint8 m_blue;
+};
+
+class CBrightLights
+{
+	static int NumBrightLights;
+	static CBrightLight aBrightLights[NUMBRIGHTLIGHTS];
+public:
+	static void Init(void);
+	static void RegisterOne(CVector pos, CVector up, CVector side, CVector front,
+		uint8 type, uint8 red = 0, uint8 green = 0, uint8 blue = 0);
+	static void Render(void);
+	static void RenderOutGeometryBuffer(void);
+};
+
+
+enum
+{
+	SHINYTEXT_WALK = 1,
+	SHINYTEXT_FLAT
+};
+
+class CShinyText
+{
+public:
+	CVector m_verts[4];
+	CVector2D m_texCoords[4];
+	float m_camDist;
+	uint8 m_type;
+	uint8 m_red;
+	uint8 m_green;
+	uint8 m_blue;
+};
+
+class CShinyTexts
+{
+	static int NumShinyTexts;
+	static CShinyText aShinyTexts[NUMSHINYTEXTS];
+public:
+	static void Init(void);
+	static void RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
+		float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
+		uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist);
+	static void Render(void);
+	static void RenderOutGeometryBuffer(void);
+};
+
+class CMoneyMessage
+{
+	friend class CMoneyMessages;
+
+	uint32	m_nTimeRegistered;
+	CVector	m_vecPosition;
+	wchar	m_aText[16];
+	CRGBA	m_Colour;
+	float	m_fSize;
+	float	m_fOpacity;
+public:
+	void Render();
+};
+
+class CMoneyMessages
+{
+	static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
+public:
+	static void Init();
+	static void Render();
+	static void	RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity);
+};
+
+class CSpecialParticleStuff
+{
+	static uint32 BoatFromStart;
+public:
+	static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
+	static void StartBoatFoamAnimation();
+	static void UpdateBoatFoamAnimation(CMatrix*);
+};
diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp
index 24577f41..8ac2315f 100644
--- a/src/render/Sprite.cpp
+++ b/src/render/Sprite.cpp
@@ -30,10 +30,12 @@ CSprite::CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh,
 	out->x *= SCREEN_WIDTH * recip;
 	out->y *= SCREEN_HEIGHT * recip;
 	// What is this? size?
-	*outw = 70.0f/CDraw::GetFOV();
-	*outh = 70.0f/CDraw::GetFOV();
-	*outw *= SCREEN_WIDTH * recip;
-	*outh *= SCREEN_HEIGHT * recip;
+	*outw = 70.0f/CDraw::GetFOV() * SCREEN_WIDTH * recip;
+#ifdef ASPECT_RATIO_SCALE
+	*outh = 70.0f/CDraw::GetFOV() / (DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO) * SCREEN_HEIGHT * recip;
+#else
+	*outh = 70.0f/CDraw::GetFOV() * SCREEN_HEIGHT * recip;
+#endif
 	return true;
 }
 
@@ -432,6 +434,7 @@ void
 CSprite::Set6Vertices2D(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
 {
 	float screenz, recipz;
+	float z = RwCameraGetNearClipPlane(Scene.camera);	// not done by game
 
 	screenz = m_f2DNearScreenZ;
 	recipz = m_fRecipNearClipPlane;
@@ -496,6 +499,7 @@ CSprite::Set6Vertices2D(RwIm2DVertex *verts, float x1, float y1, float x2, float
 		const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
 {
 	float screenz, recipz;
+	float z = RwCameraGetNearClipPlane(Scene.camera);	// not done by game
 
 	screenz = m_f2DNearScreenZ;
 	recipz = m_fRecipNearClipPlane;
diff --git a/src/render/Sprite2d.cpp b/src/render/Sprite2d.cpp
index c4dbcdaa..3f21516a 100644
--- a/src/render/Sprite2d.cpp
+++ b/src/render/Sprite2d.cpp
@@ -267,6 +267,7 @@ CSprite2d::SetVertices(float x1, float y1, float x2, float y2, float x3, float y
 		const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
 {
 	float screenz, recipz;
+	float z = RwCameraGetNearClipPlane(Scene.camera);	// not done by game
 
 	screenz = RwIm2DGetNearScreenZ();
 	recipz = RecipNearClip;
@@ -312,10 +313,11 @@ void
 CSprite2d::SetVertices(int n, float *positions, float *uvs, const CRGBA &col)
 {
 	int i;
-	float screenz, recipz;
+	float screenz, recipz, z;
 
 	screenz = RwIm2DGetNearScreenZ();
 	recipz = RecipNearClip;
+	z = RwCameraGetNearClipPlane(Scene.camera);	// not done by game
 
 
 	for(i = 0; i < n; i++){
@@ -334,10 +336,11 @@ void
 CSprite2d::SetMaskVertices(int n, float *positions)
 {
 	int i;
-	float screenz, recipz;
+	float screenz, recipz, z;
 
 	screenz = RwIm2DGetNearScreenZ();
 	recipz = RecipNearClip;
+	z = RwCameraGetNearClipPlane(Scene.camera);	// not done by game
 
 	for(i = 0; i < n; i++){
 		RwIm2DVertexSetScreenX(&maVertices[i], positions[i*2 + 0]);
@@ -345,7 +348,7 @@ CSprite2d::SetMaskVertices(int n, float *positions)
 		RwIm2DVertexSetScreenZ(&maVertices[i], screenz);
 		RwIm2DVertexSetCameraZ(&maVertices[i], z);
 		RwIm2DVertexSetRecipCameraZ(&maVertices[i], recipz);
-		RwIm2DVertexSetIntRGBA(&maVertices[i], 0, 0, 0, 0);
+		RwIm2DVertexSetIntRGBA(&maVertices[i], 255, 255, 255, 255);	// 0, 0, 0, 0 on PC
 	}
 }
 
@@ -353,10 +356,11 @@ void
 CSprite2d::SetVertices(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
 		float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
 {
-	float screenz, recipz;
+	float screenz, recipz, z;
 
 	screenz = RwIm2DGetNearScreenZ();
 	recipz = RecipNearClip;
+	z = RwCameraGetNearClipPlane(Scene.camera);	// not done by game
 
 	RwIm2DVertexSetScreenX(&verts[0], r.left);
 	RwIm2DVertexSetScreenY(&verts[0], r.top);
@@ -459,15 +463,15 @@ CSprite2d::DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const C
 
 void CSprite2d::Draw2DPolygon(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &color)
 {
-	SetVertices(x1, y1, x2, y2, x3, y3, x4, y4, color, color, color, color);
-	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, 0);
-	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
-	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(color.a != 255));
-	RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
-	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	SetVertices(x1, y1, x2, y2, x3, y3, x4, y4, color, color, color, color);
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, 0);
+	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(color.a != 255));
+	RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
 	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
 }
 
diff --git a/src/render/TexList.cpp b/src/render/TexList.cpp
new file mode 100644
index 00000000..1689837f
--- /dev/null
+++ b/src/render/TexList.cpp
@@ -0,0 +1,41 @@
+#include "common.h"
+#include "TexList.h"
+#include "rtbmp.h"
+#include "FileMgr.h"
+
+bool CTexList::ms_nTexUsed[MAX_TEXUSED];
+
+void
+CTexList::Initialise()
+{}
+
+void
+CTexList::Shutdown()
+{}
+
+RwTexture *
+CTexList::SetTexture(int32 slot, char *name)
+{
+	return nil;
+}
+
+int32
+CTexList::GetFirstFreeTexture()
+{
+	for (int32 i = 0; i < MAX_TEXUSED; i++)
+		if (!ms_nTexUsed[i])
+			return i;
+	return -1;
+}
+
+RwTexture *
+CTexList::LoadFileNameTexture(char *name)
+{
+	return SetTexture(GetFirstFreeTexture(), name);
+}
+
+void
+CTexList::LoadGlobalTextureList()
+{
+	CFileMgr::SetDir("TEXTURES");
+}
\ No newline at end of file
diff --git a/src/render/TexList.h b/src/render/TexList.h
new file mode 100644
index 00000000..7e042211
--- /dev/null
+++ b/src/render/TexList.h
@@ -0,0 +1,14 @@
+#pragma once
+
+class CTexList
+{
+	enum { MAX_TEXUSED = 400, };
+	static bool ms_nTexUsed[MAX_TEXUSED];
+public:
+	static void Initialise();
+	static void Shutdown();
+	static RwTexture *SetTexture(int32 slot, char *name);
+	static int32 GetFirstFreeTexture();
+	static RwTexture *LoadFileNameTexture(char *name);
+	static void LoadGlobalTextureList();
+};
\ No newline at end of file
diff --git a/src/render/Timecycle.h b/src/render/Timecycle.h
index 235d559c..ed4a026b 100644
--- a/src/render/Timecycle.h
+++ b/src/render/Timecycle.h
@@ -119,8 +119,10 @@ public:
 	static int GetSunCoronaBlue(void) { return m_nCurrentSunCoronaBlue; }
 	static float GetSunSize(void) { return m_fCurrentSunSize; }
 	static float GetSpriteBrightness(void) { return m_fCurrentSpriteBrightness; }
+	static float GetSpriteSize(void) { return m_fCurrentSpriteSize; }
 	static int GetShadowStrength(void) { return m_nCurrentShadowStrength; }
 	static int GetLightShadowStrength(void) { return m_nCurrentLightShadowStrength; }
+	static int GetLightOnGroundBrightness(void) { return m_fCurrentLightsOnGroundBrightness; }
 	static float GetFarClip(void) { return m_fCurrentFarClip; }
 	static float GetFogStart(void) { return m_fCurrentFogStart; }
 
@@ -136,6 +138,7 @@ public:
 	static int GetFogRed(void) { return m_nCurrentFogColourRed; }
 	static int GetFogGreen(void) { return m_nCurrentFogColourGreen; }
 	static int GetFogBlue(void) { return m_nCurrentFogColourBlue; }
+	static int GetFogReduction(void) { return m_FogReduction; }
 
 	static void Initialise(void);
 	static void Update(void);
diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp
index c1988ab4..b440e77c 100644
--- a/src/render/Weather.cpp
+++ b/src/render/Weather.cpp
@@ -2,6 +2,22 @@
 #include "patcher.h"
 #include "Weather.h"
 
+#include "Camera.h"
+#include "Clock.h"
+#include "CutsceneMgr.h"
+#include "DMAudio.h"
+#include "General.h"
+#include "Pad.h"
+#include "Particle.h"
+#include "RenderBuffer.h"
+#include "Stats.h"
+#include "Shadows.h"
+#include "Timecycle.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "World.h"
+#include "ZoneCull.h"
+
 int32 &CWeather::SoundHandle = *(int32*)0x5FFBC4;
 
 int32 &CWeather::WeatherTypeInList = *(int32*)0x8F626C;
@@ -32,13 +48,203 @@ int16 &CWeather::Stored_OldWeatherType = *(int16*)0x95CC68;
 int16 &CWeather::Stored_NewWeatherType = *(int16*)0x95CCAE;
 float &CWeather::Stored_Rain = *(float*)0x885B4C;
 
-WRAPPER void CWeather::RenderRainStreaks(void) { EAXJMP(0x524550); }
-WRAPPER void CWeather::Update(void) { EAXJMP(0x522C10); }
-WRAPPER void CWeather::Init(void) { EAXJMP(0x522BA0); }
+tRainStreak Streaks[NUM_RAIN_STREAKS];
 
-void CWeather::ReleaseWeather()
+const int16 WeatherTypesList[] = {
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_CLOUDY, WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_RAINY,
+	WEATHER_CLOUDY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_CLOUDY, WEATHER_FOGGY, WEATHER_FOGGY, WEATHER_CLOUDY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_CLOUDY, WEATHER_CLOUDY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_CLOUDY, WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_RAINY,
+	WEATHER_CLOUDY, WEATHER_RAINY, WEATHER_CLOUDY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_FOGGY, WEATHER_FOGGY, WEATHER_SUNNY,
+	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_RAINY, WEATHER_CLOUDY,
+};
+
+const float Windiness[] = {
+	0.0f, // WEATHER_SUNNY
+	0.7f, // WEATHER_CLOUDY
+	1.0f, // WEATHER_RAINY
+	0.5f  // WEATHER_FOGGY
+};
+
+#define MIN_TIME_BETWEEN_LIGHTNING_FLASH_CHANGES (50)
+
+#define RAIN_CHANGE_SPEED (0.003f)
+
+#define DROPLETS_LEFT_OFFSET (10.0f)
+#define DROPLETS_RIGHT_OFFSET (10.0f)
+#define DROPLETS_TOP_OFFSET (10.0f)
+#define DROPLETS_BOTTOM_OFFSET (10.0f)
+
+#define STREAK_U (10.0f)
+#define STREAK_V (18.0f)
+#define LARGE_STREAK_COEFFICIENT (1.23f)
+#define STREAK_MIN_DISTANCE (8.0f)
+#define STREAK_MAX_DISTANCE (16.0f)
+
+#define SPLASH_CHECK_RADIUS (7.0f)
+#define SPLASH_OFFSET_RADIUS (2.0f)
+
+#define STREAK_LIFETIME (4.0f)
+#define STREAK_INTEROLATION_TIME (0.3f)
+
+#define RAIN_COLOUR_R (200)
+#define RAIN_COLOUR_G (200)
+#define RAIN_COLOUR_B (256)
+#define RAIN_ALPHA (255)
+
+void CWeather::Init(void)
 {
-	ForcedWeatherType = -1;
+	NewWeatherType = WEATHER_SUNNY;
+	bScriptsForceRain = false;
+	OldWeatherType = WEATHER_CLOUDY;
+	Stored_StateStored = false;
+	InterpolationValue = 0.0f;
+	WhenToPlayLightningSound = 0;
+	WeatherTypeInList = 0;
+	ForcedWeatherType = WEATHER_RANDOM;
+	SoundHandle = DMAudio.CreateEntity(AUDIOTYPE_WEATHER, (void*)1);
+	if (SoundHandle >= 0)
+		DMAudio.SetEntityStatus(SoundHandle, 1);
+}
+
+void CWeather::Update(void)
+{
+	float fNewInterpolation = CClock::GetMinutes() * 1.0f / 60;
+	if (fNewInterpolation < InterpolationValue) {
+		// new hour
+		OldWeatherType = NewWeatherType;
+		if (ForcedWeatherType >= 0)
+			NewWeatherType = ForcedWeatherType;
+		else {
+			WeatherTypeInList = (WeatherTypeInList + 1) % ARRAYSIZE(WeatherTypesList);
+			NewWeatherType = WeatherTypesList[WeatherTypeInList];
+#ifdef FIX_BUGS
+		}
+		if (NewWeatherType == WEATHER_RAINY)
+			CStats::mmRain += CGeneral::GetRandomNumber() & 7;
+#else
+			if (NewWeatherType == WEATHER_RAINY)
+				CStats::mmRain += CGeneral::GetRandomNumber() & 7;
+		}
+#endif
+	}
+	InterpolationValue = fNewInterpolation;
+	if (CPad::GetPad(1)->GetRightShockJustDown()) {
+		NewWeatherType = (NewWeatherType + 1) % WEATHER_TOTAL;
+		OldWeatherType = NewWeatherType;
+	}
+
+	// Lightning
+	if (NewWeatherType != WEATHER_RAINY || OldWeatherType != WEATHER_RAINY) {
+		LightningFlash = false;
+		LightningBurst = false;
+	}
+	else{
+		if (LightningBurst) {
+			if ((CGeneral::GetRandomNumber() & 255) >= 32) {
+				// 0.875 probability
+				if (CTimer::GetTimeInMilliseconds() - LightningFlashLastChange > MIN_TIME_BETWEEN_LIGHTNING_FLASH_CHANGES) {
+					bool bOldLightningFlash = LightningFlash;
+					LightningFlash = CGeneral::GetRandomTrueFalse();
+					if (LightningFlash != bOldLightningFlash)
+						LightningFlashLastChange = CTimer::GetTimeInMilliseconds();
+				}
+			}
+			else {
+				// 0.125 probability
+				LightningBurst = false;
+				LightningDuration = min(CTimer::GetFrameCounter() - LightningStart, 20);
+				LightningFlash = false;
+				WhenToPlayLightningSound = CTimer::GetTimeInMilliseconds() + 150 * (20 - LightningDuration);
+			}
+		}
+		else {
+			if (CGeneral::GetRandomNumber() >= 200) {
+				// lower probability on PC due to randomness bug
+				LightningFlash = false;
+			}
+			else {
+				LightningBurst = true;
+				LightningStart = CTimer::GetFrameCounter();
+				LightningFlashLastChange = CTimer::GetTimeInMilliseconds();
+				LightningFlash = true;
+			}
+		}
+	}
+	if (WhenToPlayLightningSound && CTimer::GetTimeInMilliseconds() > WhenToPlayLightningSound) {
+		DMAudio.PlayOneShot(SoundHandle, SOUND_LIGHTNING, LightningDuration);
+		CPad::GetPad(0)->StartShake(40 * LightningDuration + 100, 2 * LightningDuration + 80);
+		WhenToPlayLightningSound = 0;
+	}
+
+	// Wet roads
+	if (OldWeatherType == WEATHER_RAINY) {
+		if (NewWeatherType == WEATHER_RAINY)
+			WetRoads = 1.0f;
+		else
+			WetRoads = 1.0f - InterpolationValue;
+	}
+	else {
+		if (NewWeatherType == WEATHER_RAINY)
+			WetRoads = InterpolationValue;
+		else
+			WetRoads = 0.0f;
+	}
+
+	// Rain
+	float fNewRain;
+	if (NewWeatherType == WEATHER_RAINY) {
+		// if raining for >1 hour, values: 0, 0.33, 0.66, 0.99, switching every ~16.5s
+		fNewRain = ((uint16)CTimer::GetTimeInMilliseconds() >> 14) * 0.33f;
+		if (OldWeatherType != WEATHER_RAINY) {
+			if (InterpolationValue < 0.4f)
+				// if rain has just started (<24 minutes), always 0.5
+				fNewRain = 0.5f;
+			else
+				// if rain is ongoing for >24 minutes, values: 0.25, 0.5, 0.75, 1.0, switching every ~16.5s
+				fNewRain = 0.25f + ((uint16)CTimer::GetTimeInMilliseconds() >> 14) * 0.25f;
+		}
+	}
+	else
+		fNewRain = 0.0f;
+	if (Rain != fNewRain) { // ok to use comparasion
+		if (Rain < fNewRain)
+			Rain = min(fNewRain, Rain + RAIN_CHANGE_SPEED * CTimer::GetTimeStep());
+		else
+			Rain = max(fNewRain, Rain - RAIN_CHANGE_SPEED * CTimer::GetTimeStep());
+	}
+
+	// Clouds
+	if (OldWeatherType != WEATHER_SUNNY)
+		CloudCoverage = 1.0f - InterpolationValue;
+	else
+		CloudCoverage = 0.0f;
+	if (NewWeatherType != WEATHER_SUNNY)
+		CloudCoverage += InterpolationValue;
+	
+	// Fog
+	if (OldWeatherType == WEATHER_FOGGY)
+		Foggyness = 1.0f - InterpolationValue;
+	else
+		Foggyness = 0.0f;
+	if (NewWeatherType == WEATHER_FOGGY)
+		Foggyness += InterpolationValue;
+	if (OldWeatherType == WEATHER_RAINY && NewWeatherType == WEATHER_SUNNY && InterpolationValue < 0.5f && CClock::GetHours() > 6 && CClock::GetHours() < 21)
+		Rainbow = 1.0f - 4.0f * Abs(InterpolationValue - 0.25f) / 4.0f;
+	else
+		Rainbow = 0.0f;
+	Wind = InterpolationValue * Windiness[NewWeatherType] + (1.0f - InterpolationValue) * Windiness[OldWeatherType];
+	AddRain();
 }
 
 void CWeather::ForceWeather(int16 weather)
@@ -53,6 +259,258 @@ void CWeather::ForceWeatherNow(int16 weather)
 	ForcedWeatherType = weather;
 }
 
+void CWeather::ReleaseWeather()
+{
+	ForcedWeatherType = -1;
+}
+
+void CWeather::AddRain()
+{
+	if (CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
+		return;
+	if (TheCamera.GetLookingLRBFirstPerson()) {
+		CVehicle* pVehicle = FindPlayerVehicle();
+		if (pVehicle && pVehicle->CarHasRoof()) {
+			CParticle::RemovePSystem(PARTICLE_RAINDROP_2D);
+			return;
+		}
+	}
+	if (Rain <= 0.1f)
+		return;
+	static RwRGBA colour;
+	float screen_width = RsGlobal.width;
+	float screen_height = RsGlobal.height;
+	int cur_frame = (int)(3 * Rain) & 3;
+	int num_drops = (int)(2 * Rain) + 2;
+	static int STATIC_RAIN_ANGLE = -45;
+	static int count = 1500;
+	static int add_angle = 1;
+	if (--count == 0) {
+		count = 1;
+		if (add_angle) {
+			STATIC_RAIN_ANGLE += 12;
+			if (STATIC_RAIN_ANGLE > 45) {
+				count = 1500;
+				add_angle = !add_angle;
+			}
+		}
+		else {
+			STATIC_RAIN_ANGLE -= 12;
+			if (STATIC_RAIN_ANGLE < -45) {
+				count = 1500;
+				add_angle = !add_angle;
+			}
+		}
+	}
+	float rain_angle = DEGTORAD(STATIC_RAIN_ANGLE + ((STATIC_RAIN_ANGLE < 0) ? 360 : 0));
+	float sin_angle = Sin(rain_angle);
+	float cos_angle = Cos(rain_angle);
+	float base_x = 0.0f * cos_angle - 1.0f * sin_angle;
+	float base_y = 1.0f * cos_angle + 0.0f * sin_angle;
+	CVector xpos(0.0f, 0.0f, 0.0f);
+	for (int i = 0; i < 2 * num_drops; i++) {
+		CVector dir;
+		dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+		dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+		dir.z = 0;
+		CParticle::AddParticle(PARTICLE_RAINDROP_2D, xpos, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+			colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
+		xpos.x += screen_width / (2 * num_drops);
+		xpos.x += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
+	}
+	CVector ypos(0.0f, 0.0f, 0.0f);
+	for (int i = 0; i < num_drops; i++) {
+		CVector dir;
+		dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+		dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+		dir.z = 0;
+		CParticle::AddParticle(PARTICLE_RAINDROP_2D, ypos, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+			colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
+		ypos.y += screen_width / num_drops;
+		ypos.y += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
+	}
+	CVector ypos2(0.0f, 0.0f, 0.0f);
+	for (int i = 0; i < num_drops; i++) {
+		CVector dir;
+		dir.x = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_x) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+		dir.y = (CGeneral::GetRandomNumberInRange(-0.5f, 0.5f) + base_y) * CGeneral::GetRandomNumberInRange(10.0f, 25.0f);
+		dir.z = 0;
+		CParticle::AddParticle(PARTICLE_RAINDROP_2D, ypos2, dir, nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+			colour, 0, rain_angle + CGeneral::GetRandomNumberInRange(-10, 10), cur_frame);
+		ypos2.y += screen_width / num_drops;
+		ypos2.y += CGeneral::GetRandomNumberInRange(-25.0f, 25.0f);
+	}
+	for (int i = 0; i < num_drops; i++) {
+		CVector pos;
+		pos.x = CGeneral::GetRandomNumberInRange(DROPLETS_LEFT_OFFSET, screen_width - DROPLETS_RIGHT_OFFSET);
+		pos.y = CGeneral::GetRandomNumberInRange(DROPLETS_TOP_OFFSET, screen_height - DROPLETS_TOP_OFFSET);
+		pos.z = 0.0f;
+		CParticle::AddParticle(PARTICLE_RAINDROP_2D, pos, CVector(0.0f, 0.0f, 0.0f), nil, CGeneral::GetRandomNumberInRange(0.5f, 0.9f),
+			colour, CGeneral::GetRandomNumberInRange(-10, 10), 360 - rain_angle + CGeneral::GetRandomNumberInRange(-30, 30), cur_frame, 0);
+	}
+	int num_splash_attempts = (int)(3 * Rain) + 1;
+	int num_splashes = (int)(3 * Rain) + 4;
+	CVector splash_points[4];
+	splash_points[0] = CVector(-RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+		RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+	splash_points[1] = CVector(RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+		RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+	splash_points[2] = 4.0f * CVector(-RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+		RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+	splash_points[3] = 4.0f * CVector(RwCameraGetViewWindow(TheCamera.m_pRwCamera)->x, RwCameraGetViewWindow(TheCamera.m_pRwCamera)->y, 1.0f) *
+		RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) / (RwCameraGetFarClipPlane(TheCamera.m_pRwCamera) * *(CVector2D*)RwCameraGetViewWindow(TheCamera.m_pRwCamera)).Magnitude();
+	RwV3dTransformPoints((RwV3d*)splash_points, (RwV3d*)splash_points, 4, RwFrameGetMatrix(RwCameraGetFrame(TheCamera.m_pRwCamera)));
+	CVector fp = (splash_points[0] + splash_points[1] + splash_points[2] + splash_points[3]) / 4;
+	for (int i = 0; i < num_splash_attempts; i++) {
+		CColPoint point;
+		CEntity* entity;
+		CVector np = fp + CVector(CGeneral::GetRandomNumberInRange(-SPLASH_CHECK_RADIUS, SPLASH_CHECK_RADIUS), CGeneral::GetRandomNumberInRange(-SPLASH_CHECK_RADIUS, SPLASH_CHECK_RADIUS), 0.0f);
+		if (CWorld::ProcessVerticalLine(np + CVector(0.0f, 0.0f, 40.0f), -40.0f, point, entity, true, false, false, false, true, false, nil)) {
+			for (int j = 0; j < num_splashes; j++)
+				CParticle::AddParticle((CGeneral::GetRandomTrueFalse() ? PARTICLE_RAIN_SPLASH : PARTICLE_RAIN_SPLASHUP),
+					CVector(
+						np.x + CGeneral::GetRandomNumberInRange(-SPLASH_OFFSET_RADIUS, SPLASH_OFFSET_RADIUS),
+						np.y + CGeneral::GetRandomNumberInRange(-SPLASH_OFFSET_RADIUS, SPLASH_OFFSET_RADIUS),
+						point.point.z + 0.1f),
+					CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, colour);
+		}
+	}
+}
+
+void RenderOneRainStreak(CVector pos, CVector unused, int intensity, bool scale, float distance)
+{
+	static float RandomTex;
+	static float RandomTexX;
+	static float RandomTexY;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 0] = TempBufferVerticesStored + 0;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 1] = TempBufferVerticesStored + 2;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 2] = TempBufferVerticesStored + 1;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 3] = TempBufferVerticesStored + 0;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 4] = TempBufferVerticesStored + 3;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 5] = TempBufferVerticesStored + 2;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 6] = TempBufferVerticesStored + 1;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 7] = TempBufferVerticesStored + 2;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 8] = TempBufferVerticesStored + 4;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 9] = TempBufferVerticesStored + 2;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 10] = TempBufferVerticesStored + 3;
+	TempBufferRenderIndexList[TempBufferIndicesStored + 11] = TempBufferVerticesStored + 4;
+	RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 0], 0, 0, 0, 0);
+	RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 0], pos.x + 11.0f * TheCamera.GetUp().x, pos.y + 11.0f * TheCamera.GetUp().y, pos.z + 11.0f * TheCamera.GetUp().z);
+	RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 1], 0, 0, 0, 0);
+	RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 1], pos.x - 9.0f * TheCamera.GetRight().x, pos.y - 9.0f * TheCamera.GetRight().y, pos.z - 9.0f * TheCamera.GetUp().z);
+	RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 2], RAIN_COLOUR_R * intensity / 256, RAIN_COLOUR_G * intensity / 256, RAIN_COLOUR_B * intensity / 256, RAIN_ALPHA);
+	RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 2], pos.x, pos.y, pos.z);
+	RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 3], 0, 0, 0, 0);
+	RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 3], pos.x + 9.0f * TheCamera.GetRight().x, pos.y + 9.0f * TheCamera.GetRight().y, pos.z + 9.0f * TheCamera.GetUp().z);
+	RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored + 4], 0, 0, 0, 0); 
+	RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored + 4], pos.x - 11.0f * TheCamera.GetUp().x, pos.y - 11.0f * TheCamera.GetUp().y, pos.z - 11.0f * TheCamera.GetUp().z);
+	float u = STREAK_U;
+	float v = STREAK_V;
+	if (scale) {
+		u *= LARGE_STREAK_COEFFICIENT;
+		v *= LARGE_STREAK_COEFFICIENT;
+	}
+	float distance_coefficient;
+	if (distance < STREAK_MIN_DISTANCE)
+		distance_coefficient = 1.0f;
+	else if (distance > STREAK_MAX_DISTANCE)
+		distance_coefficient = 0.5f;
+	else
+		distance_coefficient = 1.0f - 0.5f * (distance - STREAK_MIN_DISTANCE) / (STREAK_MAX_DISTANCE - STREAK_MIN_DISTANCE);
+	u *= distance_coefficient;
+	v *= distance_coefficient;
+	if (!CTimer::GetIsPaused()) {
+		RandomTex = ((CGeneral::GetRandomNumber() & 255) - 128) * 0.01f;
+		RandomTexX = (CGeneral::GetRandomNumber() & 127) * 0.01f;
+		RandomTexY = (CGeneral::GetRandomNumber() & 127) * 0.01f;
+	}
+	RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 0], 0.5f * u - RandomTex + RandomTexX);
+	RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 0], -v * 0.5f + RandomTexY);
+	RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 1], RandomTexX);
+	RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 1], RandomTexY);
+	RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 2], 0.5f * u + RandomTexX);
+	RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 2], RandomTexY);
+	RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 3], u + RandomTexX);
+	RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 3], RandomTexY);
+	RwIm3DVertexSetU(&TempBufferRenderVertices[TempBufferVerticesStored + 4], 0.5f * u + RandomTex + RandomTexX);
+	RwIm3DVertexSetV(&TempBufferRenderVertices[TempBufferVerticesStored + 5], 0.5f * v + RandomTexY);
+	TempBufferIndicesStored += 12;
+	TempBufferVerticesStored += 5;
+}
+
+void CWeather::RenderRainStreaks(void)
+{
+	if (CTimer::GetIsCodePaused())
+		return;
+	int base_intensity = (64.0f - CTimeCycle::GetFogReduction()) / 64.0f * int(255 * Rain);
+	if (base_intensity == 0)
+		return;
+	TempBufferIndicesStored = 0;
+	TempBufferVerticesStored = 0;
+	for (int i = 0; i < NUM_RAIN_STREAKS; i++) {
+		if (Streaks[i].timer) {
+			float secondsElapsed = (CTimer::GetTimeInMilliseconds() - Streaks[i].timer) / 1024.0f;
+			if (secondsElapsed > STREAK_LIFETIME)
+				Streaks[i].timer = 0;
+			else{
+				int intensity;
+				if (secondsElapsed < STREAK_INTEROLATION_TIME)
+					intensity = base_intensity * 0.5f * secondsElapsed / STREAK_INTEROLATION_TIME;
+				else if (secondsElapsed > (STREAK_LIFETIME - STREAK_INTEROLATION_TIME))
+					intensity = (STREAK_LIFETIME - secondsElapsed) * 0.5f * base_intensity / STREAK_INTEROLATION_TIME;
+				else
+					intensity = base_intensity * 0.5f;
+				CVector dir = Streaks[i].direction;
+				dir.Normalise();
+				CVector pos = Streaks[i].position + secondsElapsed * Streaks[i].direction;
+				RenderOneRainStreak(pos, dir, intensity, false, (pos - TheCamera.GetPosition()).Magnitude());
+#ifndef FIX_BUGS // remove useless code
+				if (secondsElapsed > 1.0f && secondsElapsed < STREAK_LIFETIME - 1.0f) {
+					CGeneral::GetRandomNumber(), CGeneral::GetRandomNumber();
+				}
+#endif
+			}
+		}
+		else if ((CGeneral::GetRandomNumber() & 0xF00) == 0){
+			// 1/16 probability
+			Streaks[i].direction = CVector(4.0f, 4.0f, -4.0f);
+			Streaks[i].position = 6.0f * TheCamera.GetForward() + TheCamera.GetPosition() + CVector(-1.8f * Streaks[i].direction.x, -1.8f * Streaks[i].direction.y, 8.0f);
+			if (!CCutsceneMgr::IsRunning()) {
+				Streaks[i].position.x += 2.0f * FindPlayerSpeed().x * 60.0f;
+				Streaks[i].position.y += 2.0f * FindPlayerSpeed().y * 60.0f;
+			}
+			else
+				Streaks[i].position += (TheCamera.GetPosition() - TheCamera.m_RealPreviousCameraPosition) * 20.0f;
+			Streaks[i].position.x += ((CGeneral::GetRandomNumber() & 255) - 128) * 0.08f;
+			Streaks[i].position.y += ((CGeneral::GetRandomNumber() & 255) - 128) * 0.08f;
+			Streaks[i].timer = CTimer::GetTimeInMilliseconds();
+		}
+	}
+	if (TempBufferIndicesStored){
+		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR);
+		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRainDropTex[3]));
+		if (RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, 1))
+		{
+			RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+			RwIm3DEnd();
+		}
+		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	}
+	TempBufferVerticesStored = 0;
+	TempBufferIndicesStored = 0;
+}
+
 void CWeather::StoreWeatherState()
 {
 	Stored_StateStored = true;
@@ -71,4 +529,4 @@ void CWeather::RestoreWeatherState()
 	Rain = Stored_Rain;
 	NewWeatherType = Stored_NewWeatherType;
 	OldWeatherType = Stored_OldWeatherType;
-}
\ No newline at end of file
+}
diff --git a/src/render/Weather.h b/src/render/Weather.h
index 63def9b9..9e4ea378 100644
--- a/src/render/Weather.h
+++ b/src/render/Weather.h
@@ -8,6 +8,14 @@ enum {
 class CWeather
 {
 public:
+	enum {
+		WEATHER_RANDOM = -1,
+		WEATHER_SUNNY = 0,
+		WEATHER_CLOUDY = 1,
+		WEATHER_RAINY = 2,
+		WEATHER_FOGGY = 3,
+		WEATHER_TOTAL = 4
+	};
 	static int32 &SoundHandle;
 
 	static int32 &WeatherTypeInList;
@@ -46,4 +54,18 @@ public:
 	static void ForceWeatherNow(int16);
 	static void StoreWeatherState();
 	static void RestoreWeatherState();
+	static void AddRain();
 };
+
+enum {
+	NUM_RAIN_STREAKS = 35
+};
+
+struct tRainStreak
+{
+	CVector position;
+	CVector direction;
+	uint32 timer;
+};
+
+extern RwTexture* (&gpRainDropTex)[4];
\ No newline at end of file
diff --git a/src/core/RwClumpRead.cpp b/src/rw/ClumpRead.cpp
similarity index 100%
rename from src/core/RwClumpRead.cpp
rename to src/rw/ClumpRead.cpp
diff --git a/src/render/Lights.cpp b/src/rw/Lights.cpp
similarity index 100%
rename from src/render/Lights.cpp
rename to src/rw/Lights.cpp
diff --git a/src/render/Lights.h b/src/rw/Lights.h
similarity index 100%
rename from src/render/Lights.h
rename to src/rw/Lights.h
diff --git a/src/core/NodeName.cpp b/src/rw/NodeName.cpp
similarity index 100%
rename from src/core/NodeName.cpp
rename to src/rw/NodeName.cpp
diff --git a/src/core/NodeName.h b/src/rw/NodeName.h
similarity index 100%
rename from src/core/NodeName.h
rename to src/rw/NodeName.h
diff --git a/src/core/RwHelper.cpp b/src/rw/RwHelper.cpp
similarity index 92%
rename from src/core/RwHelper.cpp
rename to src/rw/RwHelper.cpp
index 6325bf15..44ca3a0a 100644
--- a/src/core/RwHelper.cpp
+++ b/src/rw/RwHelper.cpp
@@ -3,6 +3,44 @@
 #include "patcher.h"
 #include "Timecycle.h"
 #include "skeleton.h"
+#if defined(RWLIBS) && !defined(FINAL)
+#include "rtcharse.h"
+#pragma comment( lib, "rtcharse.lib" )
+
+RtCharset *debugCharset;
+#endif
+
+void CreateDebugFont()
+{
+#if defined(RWLIBS) && !defined(FINAL)
+	RwRGBA color = { 255, 255, 128, 255 };
+	RwRGBA colorbg = { 0, 0, 0, 0 };
+	RtCharsetOpen();
+	debugCharset = RtCharsetCreate(&color, &colorbg);
+#endif
+}
+
+void DestroyDebugFont()
+{
+#if defined(RWLIBS) && !defined(FINAL)
+	RtCharsetDestroy(debugCharset);
+	RtCharsetClose();
+#endif
+}
+
+void ObrsPrintfString(const char *str, short x, short y)
+{
+#if defined(RWLIBS) && !defined(FINAL)
+	RtCharsetPrintBuffered(debugCharset, str, x, y, true);
+#endif
+}
+
+void FlushObrsPrintfs()
+{
+#if defined(RWLIBS) && !defined(FINAL)
+	RtCharsetBufferFlush();
+#endif
+}
 
 void *
 RwMallocAlign(RwUInt32 size, RwUInt32 align)
@@ -347,28 +385,6 @@ CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer)
 	return (nil);
 }
 
-WRAPPER void ReadVideoCardCapsFile(uint32&, uint32&, uint32&, uint32&) { EAXJMP(0x5926C0); }
-WRAPPER bool CheckVideoCardCaps(void) { EAXJMP(0x592740); }
-WRAPPER void WriteVideoCardCapsFile(void) { EAXJMP(0x5927D0); }
-WRAPPER void ConvertingTexturesScreen(uint32, uint32, const char*) { EAXJMP(0x592880); }
-WRAPPER void DealWithTxdWriteError(uint32, uint32, const char*) { EAXJMP(0x592BF0); }
-WRAPPER bool CreateTxdImageForVideoCard() { EAXJMP(0x592C70); }
-
-void CreateDebugFont()
-{
-	;
-}
-
-void DestroyDebugFont()
-{
-	;
-}
-
-void FlushObrsPrintfs()
-{
-	;
-}
-
 WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); }
 WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); }
 
diff --git a/src/core/RwHelper.h b/src/rw/RwHelper.h
similarity index 95%
rename from src/core/RwHelper.h
rename to src/rw/RwHelper.h
index a9f0bdf4..5b47cb6f 100644
--- a/src/core/RwHelper.h
+++ b/src/rw/RwHelper.h
@@ -5,6 +5,7 @@ void RwFreeAlign(void *mem);
 
 void CreateDebugFont();
 void DestroyDebugFont();
+void ObrsPrintfString(const char *str, short x, short y);
 void FlushObrsPrintfs();
 void DefinedState(void);
 RwFrame *GetFirstChild(RwFrame *frame);
diff --git a/src/core/RwMatFX.cpp b/src/rw/RwMatFX.cpp
similarity index 94%
rename from src/core/RwMatFX.cpp
rename to src/rw/RwMatFX.cpp
index ca9a633b..3af6fabe 100644
--- a/src/core/RwMatFX.cpp
+++ b/src/rw/RwMatFX.cpp
@@ -43,8 +43,16 @@ struct MatFX
 	int effects;
 };
 
+#ifdef RWLIBS
+extern "C" {
+	extern int MatFXMaterialDataOffset;
+	extern int MatFXAtomicDataOffset;
+	void _rpMatFXD3D8AtomicMatFXEnvRender(RxD3D8InstanceData* inst, int flags, int sel, RwTexture* texture, RwTexture* envMap);
+}
+#else
 int &MatFXMaterialDataOffset = *(int*)0x66188C;
 int &MatFXAtomicDataOffset = *(int*)0x66189C;
+#endif
 
 #ifdef PS2_MATFX
 
@@ -206,8 +214,13 @@ _rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int se
 	RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
 }
 
+
 STARTPATCHES
+#ifdef RWLIBS
+	InjectHook((uintptr)&_rpMatFXD3D8AtomicMatFXEnvRender, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP);
+#else
 	InjectHook(0x5CF6C0, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP);
+#endif
 ENDPATCHES
 
 #endif
diff --git a/src/rw/TexRead.cpp b/src/rw/TexRead.cpp
new file mode 100644
index 00000000..50b99d47
--- /dev/null
+++ b/src/rw/TexRead.cpp
@@ -0,0 +1,349 @@
+#pragma warning( push )
+#pragma warning( disable : 4005)
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
+#pragma warning( pop )
+#define WITHWINDOWS
+#include "common.h"
+#include "win.h"
+#include "patcher.h"
+#include "Timer.h"
+#ifdef GTA_PC
+#include "FileMgr.h"
+#include "Pad.h"
+#include "main.h"
+#include "Directory.h"
+#include "Streaming.h"
+#include "TxdStore.h"
+#include "CdStream.h"
+#include "Font.h"
+#include "Sprite2d.h"
+#include "Text.h"
+#include "RwHelper.h"
+#endif //GTA_PC
+
+float &texLoadTime = *(float*)0x8F1B50;
+int32 &texNumLoaded = *(int32*)0x8F252C;
+
+RwTexture*
+RwTextureGtaStreamRead(RwStream *stream)
+{
+	RwUInt32 size, version;
+	RwTexture *tex;
+
+	if(!RwStreamFindChunk(stream, rwID_TEXTURENATIVE, &size, &version))
+		return nil;
+
+	float preloadTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
+
+	if(!RWSRCGLOBAL(stdFunc[rwSTANDARDNATIVETEXTUREREAD](stream, &tex, size)))
+		return nil;
+
+	if (gGameState == GS_INIT_PLAYING_GAME) {
+		texLoadTime = (texNumLoaded * texLoadTime + (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond() - preloadTime) / (float)(texNumLoaded+1);
+		texNumLoaded++;
+	}
+	return tex;
+}
+
+RwTexture*
+destroyTexture(RwTexture *texture, void *data)
+{
+	RwTextureDestroy(texture);
+	return texture;
+}
+
+RwTexDictionary*
+RwTexDictionaryGtaStreamRead(RwStream *stream)
+{
+	RwUInt32 size, version;
+	RwInt32 numTextures;
+	RwTexDictionary *texDict;
+	RwTexture *tex;
+
+	if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
+		return nil;
+	assert(size == 4);
+	if(RwStreamRead(stream, &numTextures, size) != size)
+		return nil;
+
+	texDict = RwTexDictionaryCreate();
+	if(texDict == nil)
+		return nil;
+
+	while(numTextures--){
+		tex = RwTextureGtaStreamRead(stream);
+		if(tex == nil){
+			RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
+			RwTexDictionaryDestroy(texDict);
+			return nil;
+		}
+		RwTexDictionaryAddTexture(texDict, tex);
+	}
+
+	return texDict;
+}
+
+static int32 numberTextures = -1;
+static int32 streamPosition;
+
+RwTexDictionary*
+RwTexDictionaryGtaStreamRead1(RwStream *stream)
+{
+	RwUInt32 size, version;
+	RwInt32 numTextures;
+	RwTexDictionary *texDict;
+	RwTexture *tex;
+
+	numberTextures = 0;
+	if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
+		return nil;
+	assert(size == 4);
+	if(RwStreamRead(stream, &numTextures, size) != size)
+		return nil;
+
+	texDict = RwTexDictionaryCreate();
+	if(texDict == nil)
+		return nil;
+
+	numberTextures = numTextures/2;
+
+	while(numTextures > numberTextures){
+		numTextures--;
+
+		tex = RwTextureGtaStreamRead(stream);
+		if(tex == nil){
+			RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
+			RwTexDictionaryDestroy(texDict);
+			return nil;
+		}
+		RwTexDictionaryAddTexture(texDict, tex);
+	}
+
+	numberTextures = numTextures;
+	streamPosition = stream->Type.memory.position;
+
+	return texDict;
+}
+
+RwTexDictionary*
+RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict)
+{
+	RwTexture *tex;
+
+	RwStreamSkip(stream, streamPosition - stream->Type.memory.position);
+
+	while(numberTextures--){
+		tex = RwTextureGtaStreamRead(stream);
+		if(tex == nil){
+			RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
+			RwTexDictionaryDestroy(texDict);
+			return nil;
+		}
+		RwTexDictionaryAddTexture(texDict, tex);
+	}
+
+	return texDict;
+}
+
+#ifdef GTA_PC
+#ifdef RWLIBS
+extern "C" RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags);
+#else
+WRAPPER RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags) { EAXJMP(0x59A350); }
+#endif
+
+void
+ReadVideoCardCapsFile(uint32 &cap32, uint32 &cap24, uint32 &cap16, uint32 &cap8)
+{
+	cap32 = UINT32_MAX;
+	cap24 = UINT32_MAX;
+	cap16 = UINT32_MAX;
+	cap8 = UINT32_MAX;
+
+	int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "rb");
+	if (file != 0) {
+		CFileMgr::Read(file, (char*)&cap32, 4);
+		CFileMgr::Read(file, (char*)&cap24, 4);
+		CFileMgr::Read(file, (char*)&cap16, 4);
+		CFileMgr::Read(file, (char*)&cap8, 4);
+		CFileMgr::CloseFile(file);
+	}
+}
+
+bool
+CheckVideoCardCaps(void)
+{
+	uint32 cap32 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT8888);
+	uint32 cap24 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT888);
+	uint32 cap16 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT1555);
+	uint32 cap8 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMATPAL8 | rwRASTERFORMAT8888);
+	uint32 fcap32, fcap24, fcap16, fcap8;
+	ReadVideoCardCapsFile(fcap32, fcap24, fcap16, fcap8);
+	return cap32 != fcap32 || cap24 != fcap24 || cap16 != fcap16 || cap8 != fcap8;
+}
+
+void
+WriteVideoCardCapsFile(void)
+{
+	uint32 cap32 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT8888);
+	uint32 cap24 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT888);
+	uint32 cap16 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT1555);
+	uint32 cap8 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMATPAL8 | rwRASTERFORMAT8888);
+	int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "wb");
+	if (file != 0) {
+		CFileMgr::Write(file, (char*)&cap32, 4);
+		CFileMgr::Write(file, (char*)&cap24, 4);
+		CFileMgr::Write(file, (char*)&cap16, 4);
+		CFileMgr::Write(file, (char*)&cap8, 4);
+		CFileMgr::CloseFile(file);
+	}
+}
+
+bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
+void DoRWStuffEndOfFrame(void);
+
+void
+ConvertingTexturesScreen(uint32 num, uint32 count, const char *text)
+{
+	HandleExit();
+
+	CSprite2d *splash = LoadSplash(nil);
+	if (!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
+		return;
+
+	CSprite2d::SetRecipNearClip();
+	CSprite2d::InitPerFrame();
+	CFont::InitPerFrame();
+	DefinedState();
+
+	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+	splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
+
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(240.0f), SCREEN_SCALE_FROM_RIGHT(200.0f), SCREEN_SCALE_Y(248.0f)), CRGBA(64, 64, 64, 255));
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(240.0f), (SCREEN_SCALE_FROM_RIGHT(200.0f) - SCREEN_SCALE_X(200.0f)) * ((float)num / (float)count) + SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(248.0f)), CRGBA(255, 217, 106, 255));
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(120.0f), SCREEN_SCALE_Y(150.0f), SCREEN_SCALE_FROM_RIGHT(120.0f), SCREEN_HEIGHT - SCREEN_SCALE_Y(220.0f)), CRGBA(50, 50, 50, 210));
+
+	CFont::SetBackgroundOff();
+	CFont::SetPropOn();
+	CFont::SetScale(SCREEN_SCALE_X(0.45f), SCREEN_SCALE_Y(0.7f));
+	CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(170.0f));
+	CFont::SetJustifyOff();
+	CFont::SetColor(CRGBA(255, 217, 106, 255));
+	CFont::SetBackGroundOnlyTextOff();
+	CFont::SetFontStyle(FONT_BANK);
+	CFont::PrintString(SCREEN_SCALE_X(170.0f), SCREEN_SCALE_Y(160.0f), TheText.Get(text));
+	CFont::DrawFonts();
+	DoRWStuffEndOfFrame();
+}
+
+void
+DealWithTxdWriteError(uint32 num, uint32 count, const char *text)
+{
+	while (!RsGlobal.quit) {
+		ConvertingTexturesScreen(num, count, text);
+		CPad::UpdatePads();
+		if (CPad::GetPad(0)->GetEscapeJustDown())
+			break;
+	}
+	RsGlobal.quit = false;
+	LoadingScreen(nil, nil, nil);
+	RsGlobal.quit = true;
+}
+
+bool
+CreateTxdImageForVideoCard()
+{
+	uint8 *buf = new uint8[CDSTREAM_SECTOR_SIZE];
+	CDirectory *pDir = new CDirectory(TXDSTORESIZE);
+	CDirectory::DirectoryInfo dirInfo;
+
+	CStreaming::FlushRequestList();
+
+	RwFileFunctions *filesys = RwOsGetFileInterface();
+
+	RwStream *img = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMWRITE, "models\\txd.img");
+	if (img == nil) {
+		// original code does otherwise and it leaks
+		delete []buf;
+		delete pDir;
+
+		if (_dwOperatingSystemVersion == OS_WINNT || _dwOperatingSystemVersion == OS_WIN2000 || _dwOperatingSystemVersion == OS_WINXP)
+			DealWithTxdWriteError(0, TXDSTORESIZE, "CVT_CRT");
+
+		return false;
+	}
+
+	int32 i;
+	for (i = 0; i < TXDSTORESIZE; i++) {
+		ConvertingTexturesScreen(i, TXDSTORESIZE, "CVT_MSG");
+
+		if (CTxdStore::GetSlot(i) != nil && CStreaming::IsObjectInCdImage(i + STREAM_OFFSET_TXD)) {
+			CStreaming::RequestTxd(i, STREAMFLAGS_KEEP_IN_MEMORY);
+			CStreaming::RequestModelStream(0);
+			CStreaming::FlushChannels();
+
+			char filename[64];
+			sprintf(filename, "%s.txd", CTxdStore::GetTxdName(i));
+
+			if (CTxdStore::GetSlot(i)->texDict) {
+				int32 pos = filesys->rwftell(img->Type.file.fpFile);
+
+				if (RwTexDictionaryStreamWrite(CTxdStore::GetSlot(i)->texDict, img) == nil) {
+					DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR");
+					RwStreamClose(img, nil);
+					delete []buf;
+					delete pDir;
+					CStreaming::RemoveTxd(i);
+					return false;
+				}
+
+				int32 size = filesys->rwftell(img->Type.file.fpFile) - pos;
+				int32 num = size % CDSTREAM_SECTOR_SIZE;
+
+				size /= CDSTREAM_SECTOR_SIZE;
+				if (num != 0) {
+					size++;
+					num = CDSTREAM_SECTOR_SIZE - num;
+					RwStreamWrite(img, buf, num);
+				}
+
+				dirInfo.offset = pos / CDSTREAM_SECTOR_SIZE;
+				dirInfo.size = size;
+				strncpy(dirInfo.name, filename, sizeof(dirInfo.name));
+				pDir->AddItem(dirInfo);
+				CStreaming::RemoveTxd(i);
+			}
+			CStreaming::FlushRequestList();
+		}
+	}
+
+	RwStreamClose(img, nil);
+	delete []buf;
+
+	if (!pDir->WriteDirFile("models\\txd.dir")) {
+		DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR");
+		delete pDir;
+		return false;
+	}
+
+	delete pDir;
+
+	WriteVideoCardCapsFile();
+	return true;
+}
+#endif // GTA_PC
+
+STARTPATCHES
+	InjectHook(0x592380, RwTextureGtaStreamRead, PATCH_JUMP);
+	InjectHook(0x5924A0, RwTexDictionaryGtaStreamRead, PATCH_JUMP);
+	InjectHook(0x592550, RwTexDictionaryGtaStreamRead1, PATCH_JUMP);
+	InjectHook(0x592650, RwTexDictionaryGtaStreamRead2, PATCH_JUMP);
+
+	InjectHook(0x5926C0, ReadVideoCardCapsFile, PATCH_JUMP);
+	InjectHook(0x592740, CheckVideoCardCaps, PATCH_JUMP);
+	InjectHook(0x5927D0, WriteVideoCardCapsFile, PATCH_JUMP);
+	InjectHook(0x592880, ConvertingTexturesScreen, PATCH_JUMP);
+	InjectHook(0x592BF0, DealWithTxdWriteError, PATCH_JUMP);
+	InjectHook(0x592C70, CreateTxdImageForVideoCard, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/core/TxdStore.cpp b/src/rw/TxdStore.cpp
similarity index 100%
rename from src/core/TxdStore.cpp
rename to src/rw/TxdStore.cpp
diff --git a/src/core/TxdStore.h b/src/rw/TxdStore.h
similarity index 100%
rename from src/core/TxdStore.h
rename to src/rw/TxdStore.h
diff --git a/src/render/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp
similarity index 99%
rename from src/render/VisibilityPlugins.cpp
rename to src/rw/VisibilityPlugins.cpp
index 74cd2590..f8b1f6b2 100644
--- a/src/render/VisibilityPlugins.cpp
+++ b/src/rw/VisibilityPlugins.cpp
@@ -117,7 +117,7 @@ CVisibilityPlugins::SetRenderWareCamera(RwCamera *camera)
 RpMaterial*
 SetAlphaCB(RpMaterial *material, void *data)
 {
-	material->color.alpha = (uint8)(uint32)data;
+	((RwRGBA*)RpMaterialGetColor(material))->alpha = (uint8)(uint32)data;
 	return material;
 }
 
diff --git a/src/render/VisibilityPlugins.h b/src/rw/VisibilityPlugins.h
similarity index 100%
rename from src/render/VisibilityPlugins.h
rename to src/rw/VisibilityPlugins.h
diff --git a/src/core/rw.cpp b/src/rw/rw.cpp
similarity index 62%
rename from src/core/rw.cpp
rename to src/rw/rw.cpp
index 52bcf5bb..3875f2a1 100644
--- a/src/core/rw.cpp
+++ b/src/rw/rw.cpp
@@ -11,7 +11,8 @@ typedef RwV3d *(*rwVectorsMultFn) (RwV3d * pointsOut,
                                    const RwV3d * pointsIn,
                                    RwInt32 numPoints,
                                    const RwMatrix * matrix);
-								   
+
+#ifndef RWLIBS
 								   
 WRAPPER void _rwObjectHasFrameSetFrame(void* object, RwFrame* frame) { EAXJMP(0x5BC950); }
 WRAPPER RpAtomic* AtomicDefaultRenderCallBack(RpAtomic* atomic) { EAXJMP(0x59E690); }
@@ -412,4 +413,427 @@ WRAPPER RxNodeDefinition* RxNodeDefinitionGetAtomicEnumerateLights() { EAXJMP(0x
 WRAPPER RxNodeDefinition* RxNodeDefinitionGetMaterialScatter() { EAXJMP(0x5DDAA0); }
 WRAPPER RxNodeDefinition* RxNodeDefinitionGetLight() { EAXJMP(0x5DF040); }
 WRAPPER RxNodeDefinition* RxNodeDefinitionGetPostLight() { EAXJMP(0x5DF560); }
-WRAPPER void RxD3D8AllInOneSetRenderCallBack(RxPipelineNode* node, RxD3D8AllInOneRenderCallBack callback) { EAXJMP(0x5DFC60); }
\ No newline at end of file
+WRAPPER void RxD3D8AllInOneSetRenderCallBack(RxPipelineNode* node, RxD3D8AllInOneRenderCallBack callback) { EAXJMP(0x5DFC60); }
+#else
+
+extern "C"
+{
+    void* _rwFrameOpen(void* instance, RwInt32 offset, RwInt32 size);
+    void* _rwFrameClose(void* instance, RwInt32 offset, RwInt32 size);
+    RwFrame* _rwFrameCloneAndLinkClones(RwFrame* root);
+    RwFrame* _rwFramePurgeClone(RwFrame* root);
+    RwBool RwFrameDirty(RwFrame const* frame);
+    void _rwFrameInit(RwFrame* frame);
+    RwBool _rwMatrixSetMultFn(rwMatrixMultFn multMat);
+    void* _rwMatrixClose(void* instance, RwInt32 offset, RwInt32 size);
+    void* _rwMatrixOpen(void* instance, RwInt32 offset, RwInt32 size);
+    RwBool _rwVectorSetMultFn(rwVectorMultFn multPoint, rwVectorsMultFn multPoints, rwVectorMultFn multVector, rwVectorsMultFn multVectors);
+    void* _rwVectorClose(void* instance, RwInt32 offset, RwInt32 size);
+    void* _rwVectorOpen(void* instance, RwInt32 offset, RwInt32 size);
+    RwBool _rwPluginRegistryOpen();
+    RwBool _rwPluginRegistryClose();
+}
+
+STARTPATCHES
+InjectHook(0x5BC950, &_rwObjectHasFrameSetFrame, PATCH_JUMP);
+InjectHook(0x59E690, &AtomicDefaultRenderCallBack, PATCH_JUMP);
+InjectHook(0x59E6C0, &_rpAtomicResyncInterpolatedSphere, PATCH_JUMP);
+InjectHook(0x59E800, &RpAtomicGetWorldBoundingSphere, PATCH_JUMP);
+InjectHook(0x59ED50, &RpClumpGetNumAtomics, PATCH_JUMP);
+InjectHook(0x59ED80, &RpClumpRender, PATCH_JUMP);
+InjectHook(0x59EDD0, &RpClumpForAllAtomics, PATCH_JUMP);
+InjectHook(0x59EE10, &RpClumpForAllCameras, PATCH_JUMP);
+InjectHook(0x59EE60, &RpClumpForAllLights, PATCH_JUMP);
+InjectHook(0x59EEB0, &RpAtomicCreate, PATCH_JUMP);
+InjectHook(0x59EFA0, &RpAtomicSetGeometry, PATCH_JUMP);
+InjectHook(0x59F020, &RpAtomicDestroy, PATCH_JUMP);
+InjectHook(0x59F0A0, &RpAtomicClone, PATCH_JUMP);
+InjectHook(0x59F1B0, &RpClumpClone, PATCH_JUMP);
+InjectHook(0x59F490, &RpClumpCreate, PATCH_JUMP);
+InjectHook(0x59F500, &RpClumpDestroy, PATCH_JUMP);
+InjectHook(0x59F680, &RpClumpAddAtomic, PATCH_JUMP);
+InjectHook(0x59F6B0, &RpClumpRemoveAtomic, PATCH_JUMP);
+InjectHook(0x59F6E0, &RpClumpRemoveLight, PATCH_JUMP);
+InjectHook(0x59FC50, &RpClumpStreamRead, PATCH_JUMP);
+InjectHook(0x5A0510, &RpAtomicRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5A0540, &RpClumpRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5A0570, &RpAtomicRegisterPluginStream, PATCH_JUMP);
+InjectHook(0x5A05A0, &RpAtomicSetStreamAlwaysCallBack, PATCH_JUMP);
+InjectHook(0x5A05C0, &RpAtomicSetStreamRightsCallBack, PATCH_JUMP);
+InjectHook(0x5A05E0, &RpAtomicGetPluginOffset, PATCH_JUMP);
+InjectHook(0x5A0600, &RpAtomicSetFrame, PATCH_JUMP);
+InjectHook(0x5A0DC0, &RwEngineRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5A0DF0, &RwEngineGetPluginOffset, PATCH_JUMP);
+InjectHook(0x5A0E10, &RwEngineGetNumSubSystems, PATCH_JUMP);
+InjectHook(0x5A0E40, &RwEngineGetSubSystemInfo, PATCH_JUMP);
+InjectHook(0x5A0E70, &RwEngineGetCurrentSubSystem, PATCH_JUMP);
+InjectHook(0x5A0EA0, &RwEngineSetSubSystem, PATCH_JUMP);
+InjectHook(0x5A0ED0, &RwEngineGetNumVideoModes, PATCH_JUMP);
+InjectHook(0x5A0F00, &RwEngineGetVideoModeInfo, PATCH_JUMP);
+InjectHook(0x5A0F30, &RwEngineGetCurrentVideoMode, PATCH_JUMP);
+InjectHook(0x5A0F60, &RwEngineSetVideoMode, PATCH_JUMP);
+InjectHook(0x5A0F90, &RwEngineStop, PATCH_JUMP);
+InjectHook(0x5A0FE0, &RwEngineStart, PATCH_JUMP);
+InjectHook(0x5A1070, &RwEngineClose, PATCH_JUMP);
+InjectHook(0x5A10E0, &RwEngineOpen, PATCH_JUMP);
+InjectHook(0x5A1290, &RwEngineTerm, PATCH_JUMP);
+InjectHook(0x5A12D0, &RwEngineInit, PATCH_JUMP);
+InjectHook(0x5A15E0, &_rwFrameOpen, PATCH_JUMP);
+InjectHook(0x5A1650, &_rwFrameClose, PATCH_JUMP);
+InjectHook(0x5A1690, &_rwFrameCloneAndLinkClones, PATCH_JUMP);
+InjectHook(0x5A1880, &_rwFramePurgeClone, PATCH_JUMP);
+InjectHook(0x5A1930, &RwFrameDirty, PATCH_JUMP);
+InjectHook(0x5A1950, &_rwFrameInit, PATCH_JUMP);
+InjectHook(0x5A1A00, &RwFrameCreate, PATCH_JUMP);
+InjectHook(0x5A1A30, &RwFrameDestroy, PATCH_JUMP);
+InjectHook(0x5A1BF0, &RwFrameDestroyHierarchy, PATCH_JUMP);
+InjectHook(0x5A1C60, &RwFrameUpdateObjects, PATCH_JUMP);
+InjectHook(0x5A1CE0, &RwFrameGetLTM, PATCH_JUMP);
+InjectHook(0x5A1D00, &RwFrameAddChild, PATCH_JUMP);
+InjectHook(0x5A1ED0, &RwFrameRemoveChild, PATCH_JUMP);
+InjectHook(0x5A1FC0, &RwFrameForAllChildren, PATCH_JUMP);
+InjectHook(0x5A2000, &RwFrameTranslate, PATCH_JUMP);
+InjectHook(0x5A20A0, &RwFrameScale, PATCH_JUMP);
+InjectHook(0x5A2140, &RwFrameTransform, PATCH_JUMP);
+InjectHook(0x5A21E0, &RwFrameRotate, PATCH_JUMP);
+InjectHook(0x5A2280, &RwFrameSetIdentity, PATCH_JUMP);
+InjectHook(0x5A2340, &RwFrameForAllObjects, PATCH_JUMP);
+InjectHook(0x5A2380, &RwFrameRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5A23B0, &_rwMatrixSetMultFn, PATCH_JUMP);
+InjectHook(0x5A2520, &_rwMatrixDeterminant, PATCH_JUMP);
+InjectHook(0x5A2570, &_rwMatrixOrthogonalError, PATCH_JUMP);
+InjectHook(0x5A25D0, &_rwMatrixNormalError, PATCH_JUMP);
+InjectHook(0x5A2660, &_rwMatrixIdentityError, PATCH_JUMP);
+InjectHook(0x5A2730, &_rwMatrixClose, PATCH_JUMP);
+InjectHook(0x5A2770, &_rwMatrixOpen, PATCH_JUMP);
+InjectHook(0x5A2820, &RwMatrixOptimize, PATCH_JUMP);
+InjectHook(0x5A28E0, &RwMatrixUpdate, PATCH_JUMP);
+InjectHook(0x5A28F0, &RwMatrixMultiply, PATCH_JUMP);
+InjectHook(0x5A2960, &RwMatrixRotateOneMinusCosineSine, PATCH_JUMP);
+InjectHook(0x5A2BF0, &RwMatrixRotate, PATCH_JUMP);
+InjectHook(0x5A2C90, &RwMatrixInvert, PATCH_JUMP);
+InjectHook(0x5A2EE0, &RwMatrixScale, PATCH_JUMP);
+InjectHook(0x5A3070, &RwMatrixTranslate, PATCH_JUMP);
+InjectHook(0x5A31C0, &RwMatrixTransform, PATCH_JUMP);
+InjectHook(0x5A3300, &RwMatrixDestroy, PATCH_JUMP);
+InjectHook(0x5A3330, &RwMatrixCreate, PATCH_JUMP);
+InjectHook(0x5A3450, &_rwVectorSetMultFn, PATCH_JUMP);
+InjectHook(0x5A3600, &_rwV3dNormalize, PATCH_JUMP);
+InjectHook(0x5A36A0, &RwV3dLength, PATCH_JUMP);
+InjectHook(0x5A3710, &_rwSqrt, PATCH_JUMP);
+InjectHook(0x5A3770, &_rwInvSqrt, PATCH_JUMP);
+InjectHook(0x5A37D0, &RwV3dTransformPoints, PATCH_JUMP);
+InjectHook(0x5A37E0, &RwV3dTransformVectors, PATCH_JUMP);
+InjectHook(0x5A37F0, &_rwVectorClose, PATCH_JUMP);
+InjectHook(0x5A3860, &_rwVectorOpen, PATCH_JUMP);
+InjectHook(0x5A3AD0, &RwStreamRead, PATCH_JUMP);
+InjectHook(0x5A3C30, &RwStreamWrite, PATCH_JUMP);
+InjectHook(0x5A3DF0, &RwStreamSkip, PATCH_JUMP);
+InjectHook(0x5A3F10, &RwStreamClose, PATCH_JUMP);
+InjectHook(0x5A3FE0, &RwStreamOpen, PATCH_JUMP);
+InjectHook(0x5A43A0, &RwIm2DGetNearScreenZ, PATCH_JUMP);
+InjectHook(0x5A43B0, &RwIm2DGetFarScreenZ, PATCH_JUMP);
+InjectHook(0x5A43C0, &RwRenderStateSet, PATCH_JUMP);
+InjectHook(0x5A4410, &RwRenderStateGet, PATCH_JUMP);
+InjectHook(0x5A4420, &RwIm2DRenderLine, PATCH_JUMP);
+InjectHook(0x5A4430, &RwIm2DRenderPrimitive, PATCH_JUMP);
+InjectHook(0x5A4440, &RwIm2DRenderIndexedPrimitive, PATCH_JUMP);
+InjectHook(0x5A5020, &RwCameraEndUpdate, PATCH_JUMP);
+InjectHook(0x5A5030, &RwCameraBeginUpdate, PATCH_JUMP);
+InjectHook(0x5A5040, &RwCameraSetViewOffset, PATCH_JUMP);
+InjectHook(0x5A5070, &RwCameraSetNearClipPlane, PATCH_JUMP);
+InjectHook(0x5A5140, &RwCameraSetFarClipPlane, PATCH_JUMP);
+InjectHook(0x5A5170, &RwCameraFrustumTestSphere, PATCH_JUMP);
+InjectHook(0x5A51E0, &RwCameraClear, PATCH_JUMP);
+InjectHook(0x5A5210, &RwCameraShowRaster, PATCH_JUMP);
+InjectHook(0x5A5240, &RwCameraSetProjection, PATCH_JUMP);
+InjectHook(0x5A52B0, &RwCameraSetViewWindow, PATCH_JUMP);
+InjectHook(0x5A52F0, &RwCameraRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5A5320, &RwCameraDestroy, PATCH_JUMP);
+InjectHook(0x5A5360, &RwCameraCreate, PATCH_JUMP);
+InjectHook(0x5A7100, &RwTextureSetMipmapping, PATCH_JUMP);
+InjectHook(0x5A7120, &RwTextureGetMipmapping, PATCH_JUMP);
+InjectHook(0x5A7130, &RwTextureSetAutoMipmapping, PATCH_JUMP);
+InjectHook(0x5A7150, &RwTextureGetAutoMipmapping, PATCH_JUMP);
+InjectHook(0x5A7160, &RwTexDictionaryCreate, PATCH_JUMP);
+InjectHook(0x5A7200, &RwTexDictionaryDestroy, PATCH_JUMP);
+InjectHook(0x5A7290, &RwTexDictionaryForAllTextures, PATCH_JUMP);
+InjectHook(0x5A72D0, &RwTextureCreate, PATCH_JUMP);
+InjectHook(0x5A7330, &RwTextureDestroy, PATCH_JUMP);
+InjectHook(0x5A73B0, &RwTextureSetName, PATCH_JUMP);
+InjectHook(0x5A7420, &RwTextureSetMaskName, PATCH_JUMP);
+InjectHook(0x5A7490, &RwTexDictionaryAddTexture, PATCH_JUMP);
+InjectHook(0x5A74D0, &RwTexDictionaryFindNamedTexture, PATCH_JUMP);
+InjectHook(0x5A7550, &RwTexDictionarySetCurrent, PATCH_JUMP);
+InjectHook(0x5A7570, &RwTexDictionaryGetCurrent, PATCH_JUMP);
+InjectHook(0x5A7580, &RwTextureRead, PATCH_JUMP);
+InjectHook(0x5A7780, &RwTextureRasterGenerateMipmaps, PATCH_JUMP);
+InjectHook(0x5A9120, &RwImageCreate, PATCH_JUMP);
+InjectHook(0x5A9180, &RwImageDestroy, PATCH_JUMP);
+InjectHook(0x5A91E0, &RwImageAllocatePixels, PATCH_JUMP);
+InjectHook(0x5A92A0, &RwImageFreePixels, PATCH_JUMP);
+InjectHook(0x5A92D0, &RwImageMakeMask, PATCH_JUMP);
+InjectHook(0x5A93A0, &RwImageApplyMask, PATCH_JUMP);
+InjectHook(0x5A9750, &RwImageSetPath, PATCH_JUMP);
+InjectHook(0x5A9810, &RwImageRead, PATCH_JUMP);
+InjectHook(0x5A9B40, &RwImageFindFileType, PATCH_JUMP);
+InjectHook(0x5A9C10, &RwImageReadMaskedImage, PATCH_JUMP);
+InjectHook(0x5A9F50, &RwImageCopy, PATCH_JUMP);
+InjectHook(0x5AA130, &RwImageGammaCorrect, PATCH_JUMP);
+InjectHook(0x5AA2C0, &RwImageSetGamma, PATCH_JUMP);
+InjectHook(0x5AA4E0, &_rwStreamWriteVersionedChunkHeader, PATCH_JUMP);
+InjectHook(0x5AA540, &RwStreamFindChunk, PATCH_JUMP);
+InjectHook(0x5AA640, &RwMemLittleEndian32, PATCH_JUMP);
+InjectHook(0x5AA650, &RwMemNative32, PATCH_JUMP);
+InjectHook(0x5AA660, &RwMemFloat32ToReal, PATCH_JUMP);
+InjectHook(0x5AA680, &RwStreamWriteReal, PATCH_JUMP);
+InjectHook(0x5AA720, &RwStreamWriteInt32, PATCH_JUMP);
+InjectHook(0x5AA740, &RwStreamReadReal, PATCH_JUMP);
+InjectHook(0x5AA7B0, &RwStreamReadInt32, PATCH_JUMP);
+InjectHook(0x5AA800, &RwTextureStreamGetSize, PATCH_JUMP);
+InjectHook(0x5AA870, &RwTextureStreamWrite, PATCH_JUMP);
+InjectHook(0x5AAA40, &RwTextureStreamRead, PATCH_JUMP);
+InjectHook(0x5AB020, &RwTexDictionaryStreamWrite, PATCH_JUMP);
+InjectHook(0x5AC890, &RpMorphTargetCalcBoundingSphere, PATCH_JUMP);
+InjectHook(0x5AC9A0, &RpGeometryAddMorphTargets, PATCH_JUMP);
+InjectHook(0x5ACB60, &RpGeometryTriangleSetVertexIndices, PATCH_JUMP);
+InjectHook(0x5ACB90, &RpGeometryTriangleSetMaterial, PATCH_JUMP);
+InjectHook(0x5ACBF0, &RpGeometryForAllMaterials, PATCH_JUMP);
+InjectHook(0x5ACC30, &RpGeometryLock, PATCH_JUMP);
+InjectHook(0x5ACC60, &RpGeometryUnlock, PATCH_JUMP);
+InjectHook(0x5ACD10, &RpGeometryCreate, PATCH_JUMP);
+InjectHook(0x5ACF40, &_rpGeometryAddRef, PATCH_JUMP);
+InjectHook(0x5ACF50, &RpGeometryDestroy, PATCH_JUMP);
+InjectHook(0x5ACFF0, &RpGeometryRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5AD020, &RpGeometryRegisterPluginStream, PATCH_JUMP);
+InjectHook(0x5AD050, &RpGeometryStreamRead, PATCH_JUMP);
+InjectHook(0x5AD6D0, &RwRasterGetCurrentContext, PATCH_JUMP);
+InjectHook(0x5AD6F0, &RwRasterUnlock, PATCH_JUMP);
+InjectHook(0x5AD710, &RwRasterRenderFast, PATCH_JUMP);
+InjectHook(0x5AD750, &RwRasterUnlockPalette, PATCH_JUMP);
+InjectHook(0x5AD780, &RwRasterDestroy, PATCH_JUMP);
+InjectHook(0x5AD7C0, &RwRasterPushContext, PATCH_JUMP);
+InjectHook(0x5AD810, &RwRasterRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5AD840, &RwRasterLockPalette, PATCH_JUMP);
+InjectHook(0x5AD870, &RwRasterPopContext, PATCH_JUMP);
+InjectHook(0x5AD8C0, &RwRasterGetNumLevels, PATCH_JUMP);
+InjectHook(0x5AD900, &RwRasterShowRaster, PATCH_JUMP);
+InjectHook(0x5AD930, &RwRasterCreate, PATCH_JUMP);
+InjectHook(0x5AD9D0, &RwRasterLock, PATCH_JUMP);
+InjectHook(0x5ADC30, &RpMaterialCreate, PATCH_JUMP);
+InjectHook(0x5ADCB0, &RpMaterialDestroy, PATCH_JUMP);
+InjectHook(0x5ADD10, &RpMaterialSetTexture, PATCH_JUMP);
+InjectHook(0x5ADD40, &RpMaterialRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5ADD70, &RpMaterialRegisterPluginStream, PATCH_JUMP);
+InjectHook(0x5ADDA0, &RpMaterialStreamRead, PATCH_JUMP);
+InjectHook(0x5AE0B0, &_rpSectorDefaultRenderCallBack, PATCH_JUMP);
+InjectHook(0x5AE100, &_rpWorldForAllGlobalLights, PATCH_JUMP);
+InjectHook(0x5AE150, &_rpWorldSectorForAllLocalLights, PATCH_JUMP);
+InjectHook(0x5AE190, &RpWorldUnlock, PATCH_JUMP);
+InjectHook(0x5AE2B0, &RpWorldSectorGetWorld, PATCH_JUMP);
+InjectHook(0x5AE340, &RpWorldDestroy, PATCH_JUMP);
+InjectHook(0x5AE6A0, &RpWorldCreate, PATCH_JUMP);
+InjectHook(0x5AEA40, &RpWorldRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5AEA70, &RpWorldRegisterPluginStream, PATCH_JUMP);
+InjectHook(0x5AEAA0, &RpWorldPluginAttach, PATCH_JUMP);
+InjectHook(0x5AFB80, &RpWorldAddCamera, PATCH_JUMP);
+InjectHook(0x5AFBB0, &RpWorldRemoveCamera, PATCH_JUMP);
+InjectHook(0x5AFC10, &RpAtomicGetWorld, PATCH_JUMP);
+InjectHook(0x5AFC20, &RpWorldAddClump, PATCH_JUMP);
+InjectHook(0x5AFDA0, &RpWorldAddLight, PATCH_JUMP);
+InjectHook(0x5AFDF0, &RpWorldRemoveLight, PATCH_JUMP);
+InjectHook(0x5AFE70, &RtBMPImageRead, PATCH_JUMP);
+InjectHook(0x5B07D0, &RpSkinPluginAttach, PATCH_JUMP);
+InjectHook(0x5B1050, &RpSkinAtomicSetHAnimHierarchy, PATCH_JUMP);
+InjectHook(0x5B1070, &RpSkinAtomicGetHAnimHierarchy, PATCH_JUMP);
+InjectHook(0x5B1080, &RpSkinGeometryGetSkin, PATCH_JUMP);
+InjectHook(0x5B1090, &RpSkinGeometrySetSkin, PATCH_JUMP);
+InjectHook(0x5B10D0, &RpSkinGetSkinToBoneMatrices, PATCH_JUMP);
+InjectHook(0x5B10E0, &RpHAnimHierarchyCreate, PATCH_JUMP);
+InjectHook(0x5B11F0, &RpHAnimFrameGetHierarchy, PATCH_JUMP);
+InjectHook(0x5B1200, &RpHAnimHierarchySetCurrentAnim, PATCH_JUMP);
+InjectHook(0x5B12B0, &RpHAnimHierarchySubAnimTime, PATCH_JUMP);
+InjectHook(0x5B1480, &RpHAnimHierarchyAddAnimTime, PATCH_JUMP);
+InjectHook(0x5B1780, &RpHAnimHierarchyUpdateMatrices, PATCH_JUMP);
+InjectHook(0x5B1C10, &RpHAnimAnimationStreamRead, PATCH_JUMP);
+InjectHook(0x5B1D50, &RpHAnimPluginAttach, PATCH_JUMP);
+InjectHook(0x5B2640, &RpMatFXPluginAttach, PATCH_JUMP);
+InjectHook(0x5B3750, &RpMatFXAtomicEnableEffects, PATCH_JUMP);
+InjectHook(0x5B3780, &RpMatFXMaterialSetEffects, PATCH_JUMP);
+InjectHook(0x5B38D0, &RpMatFXMaterialSetupEnvMap, PATCH_JUMP);
+InjectHook(0x5B3A40, &RpMatFXMaterialSetBumpMapTexture, PATCH_JUMP);
+InjectHook(0x5B3CF0, &RwD3D8SetRenderState, PATCH_JUMP);
+InjectHook(0x5B3D40, &RwD3D8GetRenderState, PATCH_JUMP);
+InjectHook(0x5B3D60, &RwD3D8SetTextureStageState, PATCH_JUMP);
+InjectHook(0x5B53A0, &RwD3D8SetTexture, PATCH_JUMP);
+InjectHook(0x5B6720, &RwIm3DTransform, PATCH_JUMP);
+InjectHook(0x5B67F0, &RwIm3DEnd, PATCH_JUMP);
+InjectHook(0x5B6820, &RwIm3DRenderIndexedPrimitive, PATCH_JUMP);
+InjectHook(0x5B6980, &RwIm3DRenderLine, PATCH_JUMP);
+InjectHook(0x5B6A50, &RwIm3DSetTransformPipeline, PATCH_JUMP);
+InjectHook(0x5B6AC0, &RwIm3DSetRenderPipeline, PATCH_JUMP);
+InjectHook(0x5B95D0, &RwD3D8EngineSetRefreshRate, PATCH_JUMP);
+InjectHook(0x5B9640, &RwD3D8CameraAttachWindow, PATCH_JUMP);
+InjectHook(0x5BAEB0, &RwD3D8DeviceSupportsDXTTexture, PATCH_JUMP);
+InjectHook(0x5BAF90, &RwD3D8SetVertexShader, PATCH_JUMP);
+InjectHook(0x5BAFD0, &RwD3D8SetPixelShader, PATCH_JUMP);
+InjectHook(0x5BB010, &RwD3D8SetStreamSource, PATCH_JUMP);
+InjectHook(0x5BB060, &RwD3D8SetIndices, PATCH_JUMP);
+InjectHook(0x5BB0B0, &RwD3D8DrawIndexedPrimitive, PATCH_JUMP);
+InjectHook(0x5BB140, &RwD3D8DrawPrimitive, PATCH_JUMP);
+InjectHook(0x5BB1D0, &RwD3D8SetTransform, PATCH_JUMP);
+InjectHook(0x5BB310, &RwD3D8GetTransform, PATCH_JUMP);
+InjectHook(0x5BB340, &RwD3D8SetTransformWorld, PATCH_JUMP);
+InjectHook(0x5BB490, &RwD3D8SetSurfaceProperties, PATCH_JUMP);
+InjectHook(0x5BB7A0, &RwD3D8SetLight, PATCH_JUMP);
+InjectHook(0x5BB890, &RwD3D8EnableLight, PATCH_JUMP);
+InjectHook(0x5BB9F0, &RwD3D8DynamicVertexBufferCreate, PATCH_JUMP);
+InjectHook(0x5BBAE0, &RwD3D8DynamicVertexBufferDestroy, PATCH_JUMP);
+InjectHook(0x5BBB10, &RwD3D8IndexBufferCreate, PATCH_JUMP);
+InjectHook(0x5BBB40, &RwD3D8CreatePixelShader, PATCH_JUMP);
+InjectHook(0x5BBB90, &RwD3D8DeletePixelShader, PATCH_JUMP);
+InjectHook(0x5BBC00, &RwD3D8SetPixelShaderConstant, PATCH_JUMP);
+InjectHook(0x5BBC30, &RwD3D8GetCaps, PATCH_JUMP);
+InjectHook(0x5BBC40, &RwD3D8CameraIsSphereFullyInsideFrustum, PATCH_JUMP);
+InjectHook(0x5BBCA0, &RwD3D8CameraIsBBoxFullyInsideFrustum, PATCH_JUMP);
+InjectHook(0x5BBD30, &RwD3D8DynamicVertexBufferLock, PATCH_JUMP);
+InjectHook(0x5BBEB0, &RwD3D8DynamicVertexBufferUnlock, PATCH_JUMP);
+InjectHook(0x5BBED0, &_rwIntelSSEsupported, PATCH_JUMP);
+InjectHook(0x5BBF10, &RwImageSetFromRaster, PATCH_JUMP);
+InjectHook(0x5BBF50, &RwRasterSetFromImage, PATCH_JUMP);
+InjectHook(0x5BBF80, &RwImageFindRasterFormat, PATCH_JUMP);
+InjectHook(0x5BBFF0, &RwFrameRegisterPluginStream, PATCH_JUMP);
+InjectHook(0x5BC020, &_rwFrameListDeinitialize, PATCH_JUMP);
+InjectHook(0x5BC050, &_rwFrameListStreamRead, PATCH_JUMP);
+InjectHook(0x5BC300, &RpLightSetRadius, PATCH_JUMP);
+InjectHook(0x5BC320, &RpLightSetColor, PATCH_JUMP);
+InjectHook(0x5BC370, &RpLightGetConeAngle, PATCH_JUMP);
+InjectHook(0x5BC5B0, &RpLightRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5BC5E0, &RpLightStreamRead, PATCH_JUMP);
+InjectHook(0x5BC780, &RpLightDestroy, PATCH_JUMP);
+InjectHook(0x5BC7C0, &RpLightCreate, PATCH_JUMP);
+InjectHook(0x5BE280, &_rwD3D8TexDictionaryEnableRasterFormatConversion, PATCH_JUMP);
+InjectHook(0x5BF110, &RwOsGetFileInterface, PATCH_JUMP);
+InjectHook(0x5C1720, &RwFreeListDestroy, PATCH_JUMP);
+InjectHook(0x5C1790, &RwFreeListCreate, PATCH_JUMP);
+InjectHook(0x5C19F0, &RwFreeListPurge, PATCH_JUMP);
+InjectHook(0x5C1B90, &RwFreeListPurgeAllFreeLists, PATCH_JUMP);
+InjectHook(0x5C1D40, &RwFreeListForAllUsed, PATCH_JUMP);
+InjectHook(0x5C2780, &_rxPipelineClose, PATCH_JUMP);
+InjectHook(0x5C27E0, &_rxPipelineOpen, PATCH_JUMP);
+InjectHook(0x5C2AD0, &RxHeapGetGlobalHeap, PATCH_JUMP);
+InjectHook(0x5C2AE0, &RxPacketCreate, PATCH_JUMP);
+InjectHook(0x5C2B10, &RxClusterSetExternalData, PATCH_JUMP);
+InjectHook(0x5C2B70, &RxClusterSetData, PATCH_JUMP);
+InjectHook(0x5C2BD0, &RxClusterInitializeData, PATCH_JUMP);
+InjectHook(0x5C2C40, &RxClusterResizeData, PATCH_JUMP);
+InjectHook(0x5C2C90, &RxClusterLockWrite, PATCH_JUMP);
+InjectHook(0x5C2D60, &RxPipelineExecute, PATCH_JUMP);
+InjectHook(0x5C2E00, &RxPipelineCreate, PATCH_JUMP);
+InjectHook(0x5C2E70, &_rxPipelineDestroy, PATCH_JUMP);
+InjectHook(0x5C3080, &RwResourcesFreeResEntry, PATCH_JUMP);
+InjectHook(0x5C30F0, &_rwResourcesPurge, PATCH_JUMP);
+InjectHook(0x5C3170, &RwResourcesAllocateResEntry, PATCH_JUMP);
+InjectHook(0x5C3360, &RwResourcesEmptyArena, PATCH_JUMP);
+InjectHook(0x5C3450, &_rwPluginRegistryOpen, PATCH_JUMP);
+InjectHook(0x5C3480, &_rwPluginRegistryClose, PATCH_JUMP);
+InjectHook(0x5C3590, &_rwPluginRegistryGetPluginOffset, PATCH_JUMP);
+InjectHook(0x5C35C0, &_rwPluginRegistryAddPlugin, PATCH_JUMP);
+InjectHook(0x5C37F0, &_rwPluginRegistryInitObject, PATCH_JUMP);
+InjectHook(0x5C3850, &_rwPluginRegistryDeInitObject, PATCH_JUMP);
+InjectHook(0x5C3880, &_rwPluginRegistryCopyObject, PATCH_JUMP);
+InjectHook(0x5C3910, &RwErrorSet, PATCH_JUMP);
+InjectHook(0x5C3970, &_rwerror, PATCH_JUMP);
+InjectHook(0x5C3980, &_rwPluginRegistryAddPluginStream, PATCH_JUMP);
+InjectHook(0x5C39C0, &_rwPluginRegistryAddPlgnStrmlwysCB, PATCH_JUMP);
+InjectHook(0x5C39F0, &_rwPluginRegistryAddPlgnStrmRightsCB, PATCH_JUMP);
+InjectHook(0x5C3A20, & _rwPluginRegistryReadDataChunks, PATCH_JUMP);
+InjectHook(0x5C3B50, & _rwPluginRegistryInvokeRights, PATCH_JUMP);
+InjectHook(0x5C3BA0, &_rwPluginRegistryGetSize, PATCH_JUMP);
+InjectHook(0x5C3BE0, &_rwPluginRegistryWriteDataChunks, PATCH_JUMP);
+InjectHook(0x5C3CB0, &_rwPluginRegistrySkipDataChunks, PATCH_JUMP);
+InjectHook(0x5C3D30, &RwCameraStreamRead, PATCH_JUMP);
+InjectHook(0x5C5570, &RwBBoxCalculate, PATCH_JUMP);
+InjectHook(0x5C72B0, &RwImageResample, PATCH_JUMP);
+InjectHook(0x5C7B30, &RwImageCreateResample, PATCH_JUMP);
+InjectHook(0x5D9240, &RxRenderStateVectorSetDefaultRenderStateVector, PATCH_JUMP);
+InjectHook(0x5D9340, &RxRenderStateVectorCreate, PATCH_JUMP);
+InjectHook(0x5D9410, &RxRenderStateVectorDestroy, PATCH_JUMP);
+InjectHook(0x5D9460, &RxRenderStateVectorLoadDriverState, PATCH_JUMP);
+InjectHook(0x5D95D0, &_rxEmbeddedPacketBetweenPipelines, PATCH_JUMP);
+InjectHook(0x5D9740, &_rxEmbeddedPacketBetweenNodes, PATCH_JUMP);
+InjectHook(0x5D9810, &_rxPacketDestroy, PATCH_JUMP);
+InjectHook(0x5C8B10, &_rpMaterialListDeinitialize, PATCH_JUMP);
+InjectHook(0x5C8B70, &_rpMaterialListInitialize, PATCH_JUMP);
+InjectHook(0x5C8B80, &_rpMaterialListGetMaterial, PATCH_JUMP);
+InjectHook(0x5C8B90, &_rpMaterialListAppendMaterial, PATCH_JUMP);
+InjectHook(0x5C8C50, &_rpMaterialListFindMaterialIndex, PATCH_JUMP);
+InjectHook(0x5C8C80, &_rpMaterialListStreamRead, PATCH_JUMP);
+InjectHook(0x5C8FE0, &_rpMeshHeaderCreate, PATCH_JUMP);
+InjectHook(0x5C8FF0, &_rpMeshClose, PATCH_JUMP);
+InjectHook(0x5C9020, &_rpMeshOpen, PATCH_JUMP);
+InjectHook(0x5C9140, &_rpBuildMeshCreate, PATCH_JUMP);
+InjectHook(0x5C9220, &_rpBuildMeshDestroy, PATCH_JUMP);
+InjectHook(0x5C9260, &_rpMeshDestroy, PATCH_JUMP);
+InjectHook(0x5C92A0, &_rpBuildMeshAddTriangle, PATCH_JUMP);
+InjectHook(0x5C9380, &_rpMeshHeaderForAllMeshes, PATCH_JUMP);
+InjectHook(0x5C93C0, &_rpMeshWrite, PATCH_JUMP);
+InjectHook(0x5C9510, &_rpMeshRead, PATCH_JUMP);
+InjectHook(0x5C96E0, &_rpMeshSize, PATCH_JUMP);
+InjectHook(0x5C9730, &RpBuildMeshGenerateDefaultTriStrip, PATCH_JUMP);
+InjectHook(0x5CAE10, &_rpTriListMeshGenerate, PATCH_JUMP);
+InjectHook(0x5CB230, &_rpMeshOptimise, PATCH_JUMP);
+InjectHook(0x5CB2B0, &RpWorldSectorRegisterPlugin, PATCH_JUMP);
+InjectHook(0x5CB2E0, &RpWorldSectorRegisterPluginStream, PATCH_JUMP);
+InjectHook(0x5CB630, &RpWorldSetDefaultSectorPipeline, PATCH_JUMP);
+InjectHook(0x5CB670, &RpAtomicSetDefaultPipeline, PATCH_JUMP);
+InjectHook(0x5CDEE0, &RpHAnimStdKeyFrameToMatrix, PATCH_JUMP);
+InjectHook(0x5CE000, &RpHAnimStdKeyFrameInterpolate, PATCH_JUMP);
+InjectHook(0x5CE420, &RpHAnimStdKeyFrameBlend, PATCH_JUMP);
+InjectHook(0x5CE820, &RpHAnimStdKeyFrameStreamRead, PATCH_JUMP);
+InjectHook(0x5CE8C0, &RpHAnimStdKeyFrameStreamWrite, PATCH_JUMP);
+InjectHook(0x5CE930, &RpHAnimStdKeyFrameStreamGetSize, PATCH_JUMP);
+InjectHook(0x5CE950, &RpHAnimStdKeyFrameMulRecip, PATCH_JUMP);
+InjectHook(0x5CEAB0, &RpHAnimStdKeyFrameAdd, PATCH_JUMP);
+InjectHook(0x5D1070, &RxHeapFree, PATCH_JUMP);
+InjectHook(0x5D1260, &RxHeapAlloc, PATCH_JUMP);
+InjectHook(0x5D14D0, &RxHeapRealloc, PATCH_JUMP);
+InjectHook(0x5D1680, &_rxHeapReset, PATCH_JUMP);
+InjectHook(0x5D16F0, &RxHeapDestroy, PATCH_JUMP);
+InjectHook(0x5D1750, &RxHeapCreate, PATCH_JUMP);
+InjectHook(0x5D1EC0, &RxPipelineNodeFindOutputByName, PATCH_JUMP);
+InjectHook(0x5D1F20, &RxPipelineNodeFindInput, PATCH_JUMP);
+InjectHook(0x5D1F30, &RxPipelineNodeRequestCluster, PATCH_JUMP);
+InjectHook(0x5D1FA0, &RxLockedPipeUnlock, PATCH_JUMP);
+InjectHook(0x5D29F0, &RxPipelineLock, PATCH_JUMP);
+InjectHook(0x5D2B10, &RxPipelineFindNodeByName, PATCH_JUMP);
+InjectHook(0x5D2BA0, &RxLockedPipeAddFragment, PATCH_JUMP);
+InjectHook(0x5D2EE0, &RxLockedPipeAddPath, PATCH_JUMP);
+InjectHook(0x5D31C0, &RxNodeDefinitionGetImmRenderSetup, PATCH_JUMP);
+InjectHook(0x5D35C0, &RxNodeDefinitionGetImmMangleTriangleIndices, PATCH_JUMP);
+InjectHook(0x5D3C60, &RxNodeDefinitionGetCullTriangle, PATCH_JUMP);
+InjectHook(0x5D4F80, &RxNodeDefinitionGetClipTriangle, PATCH_JUMP);
+InjectHook(0x5D51C0, &RxNodeDefinitionGetSubmitTriangle, PATCH_JUMP);
+InjectHook(0x5D5400, &RxNodeDefinitionGetImmInstance, PATCH_JUMP);
+InjectHook(0x5D6000, &RxNodeDefinitionGetTransform, PATCH_JUMP);
+InjectHook(0x5D61C0, &RxNodeDefinitionGetImmStash, PATCH_JUMP);
+InjectHook(0x5D6470, &RxNodeDefinitionGetImmMangleLineIndices, PATCH_JUMP);
+InjectHook(0x5D7230, &RxNodeDefinitionGetClipLine, PATCH_JUMP);
+InjectHook(0x5D74C0, &RxNodeDefinitionGetSubmitLine, PATCH_JUMP);
+InjectHook(0x5D9C90, &_rwD3D8LightsOpen, PATCH_JUMP);
+InjectHook(0x5D9EF0, &_rwD3D8LightsClose, PATCH_JUMP);
+InjectHook(0x5D9F80, &_rwD3D8LightsGlobalEnable, PATCH_JUMP);
+InjectHook(0x5DA210, &_rwD3D8LightLocalEnable, PATCH_JUMP);
+InjectHook(0x5DA450, &_rwD3D8LightsEnable, PATCH_JUMP);
+InjectHook(0x5DAAC0, &RxNodeDefinitionGetD3D8WorldSectorAllInOne, PATCH_JUMP);
+InjectHook(0x5DC500, &RxNodeDefinitionGetD3D8AtomicAllInOne, PATCH_JUMP);
+InjectHook(0x5DCC50, &RxNodeDefinitionGetWorldSectorInstance, PATCH_JUMP);
+InjectHook(0x5DCD80, &RxNodeDefinitionGetWorldSectorEnumerateLights, PATCH_JUMP);
+InjectHook(0x5DD800, &RxNodeDefinitionGetAtomicInstance, PATCH_JUMP);
+InjectHook(0x5DD9B0, &RxNodeDefinitionGetAtomicEnumerateLights, PATCH_JUMP);
+InjectHook(0x5DDAA0, &RxNodeDefinitionGetMaterialScatter, PATCH_JUMP);
+InjectHook(0x5DF040, &RxNodeDefinitionGetLight, PATCH_JUMP);
+InjectHook(0x5DF560, &RxNodeDefinitionGetPostLight, PATCH_JUMP);
+InjectHook(0x5DFC60, &RxD3D8AllInOneSetRenderCallBack, PATCH_JUMP);
+ENDPATCHES
+#endif
\ No newline at end of file
diff --git a/src/save/Date.h b/src/save/Date.h
index 3e022d09..15646c23 100644
--- a/src/save/Date.h
+++ b/src/save/Date.h
@@ -1,18 +1,18 @@
-#pragma once
-
-class CDate
-{
-public:
-	int m_nSecond;
-	int m_nMinute;
-	int m_nHour;
-	int m_nDay;
-	int m_nMonth;
-	int m_nYear;
-	
-	CDate();
-	bool operator>(const CDate &right);
-	bool operator<(const CDate &right);
-	bool operator==(const CDate &right);
-	void PopulateDateFields(int8 &second, int8 &minute, int8 &hour, int8 &day, int8 &month, int16 year);
+#pragma once
+
+class CDate
+{
+public:
+	int m_nSecond;
+	int m_nMinute;
+	int m_nHour;
+	int m_nDay;
+	int m_nMonth;
+	int m_nYear;
+	
+	CDate();
+	bool operator>(const CDate &right);
+	bool operator<(const CDate &right);
+	bool operator==(const CDate &right);
+	void PopulateDateFields(int8 &second, int8 &minute, int8 &hour, int8 &day, int8 &month, int16 year);
 };
\ No newline at end of file
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index d71b0c22..0ec0b117 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -9,17 +9,20 @@
 #include "Clock.h"
 #include "Date.h"
 #include "FileMgr.h"
+#include "Frontend.h"
 #include "GameLogic.h"
 #include "Gangs.h"
 #include "Garages.h"
 #include "GenericGameStorage.h"
 #include "Pad.h"
+#include "Particle.h"
 #include "ParticleObject.h"
 #include "PathFind.h"
 #include "PCSave.h"
 #include "Phones.h"
 #include "Pickups.h"
 #include "PlayerPed.h"
+#include "ProjectileInfo.h"
 #include "Pools.h"
 #include "Radar.h"
 #include "Restart.h"
@@ -48,13 +51,35 @@ char SaveFileNameJustSaved[260];
 int (&Slots)[SLOT_COUNT+1] = *(int(*)[SLOT_COUNT+1])*(uintptr*)0x72803C;
 CDate &CompileDateAndTime = *(CDate*)0x72BCB8;
 
+bool &b_FoundRecentSavedGameWantToLoad = *(bool*)0x95CDA8;
+bool &JustLoadedDontFadeInYet = *(bool*)0x95CDB4;
+bool &StillToFadeOut = *(bool*)0x95CD99;
+uint32 &TimeStartedCountingForFade = *(uint32*)0x9430EC;
+uint32 &TimeToStayFadedBeforeFadeOut = *(uint32*)0x611564;
+
 #define ReadDataFromBufferPointer(buf, to) memcpy(&to, buf, sizeof(to)); buf += align4bytes(sizeof(to));
 #define WriteDataToBufferPointer(buf, from) memcpy(buf, &from, sizeof(from)); buf += align4bytes(sizeof(from));
 
-WRAPPER bool GenericLoad() { EAXJMP(0x590A00); }
+#define LoadSaveDataBlock()\
+do {\
+	if (!ReadDataFromFile(file, (uint8 *) &size, 4))\
+		return false;\
+	size = align4bytes(size);\
+	if (!ReadDataFromFile(file, work_buff, size))\
+		return false;\
+	buf = work_buff;\
+} while (0)
 
+#define ReadDataFromBlock(msg,load_func)\
+do {\
+	debug(msg);\
+	ReadDataFromBufferPointer(buf, size);\
+	load_func(buf, size);\
+	size = align4bytes(size);\
+	buf += size;\
+} while (0)
 
-#define WRITE_BLOCK(save_func)\
+#define WriteSaveDataBlock(save_func)\
 do {\
 	buf = work_buff;\
 	reserved = 0;\
@@ -110,11 +135,11 @@ GenericSave(int file)
 	WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes);
 	currPad = CPad::GetPad(0);
 	WriteDataToBufferPointer(buf, currPad->Mode);
-	WriteDataToBufferPointer(buf, CTimer::GetTimeInMilliseconds());
-	WriteDataToBufferPointer(buf, CTimer::GetTimeScale());
-	WriteDataToBufferPointer(buf, CTimer::GetTimeStep());
-	WriteDataToBufferPointer(buf, CTimer::GetTimeStepNonClipped());
-	WriteDataToBufferPointer(buf, CTimer::GetFrameCounter());
+	WriteDataToBufferPointer(buf, CTimer::m_snTimeInMilliseconds);
+	WriteDataToBufferPointer(buf, CTimer::ms_fTimeScale);
+	WriteDataToBufferPointer(buf, CTimer::ms_fTimeStep);
+	WriteDataToBufferPointer(buf, CTimer::ms_fTimeStepNonClipped);
+	WriteDataToBufferPointer(buf, CTimer::m_FrameCounter);
 	WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep);
 	WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate);
 	WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale);
@@ -131,7 +156,6 @@ GenericSave(int file)
 	WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList);
 	WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator);
 	WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator);
-
 	assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
 
 	// Save scripts, block is nested within the same block as simple vars for some reason
@@ -146,25 +170,25 @@ GenericSave(int file)
 	totalSize = buf - work_buff;
 
 	// Save the rest
-	WRITE_BLOCK(CPools::SavePedPool);
-	WRITE_BLOCK(CGarages::Save);
-	WRITE_BLOCK(CPools::SaveVehiclePool);
-	WRITE_BLOCK(CPools::SaveObjectPool);
-	WRITE_BLOCK(ThePaths.Save);
-	WRITE_BLOCK(CCranes::Save);
-	WRITE_BLOCK(CPickups::Save);
-	WRITE_BLOCK(gPhoneInfo.Save);
-	WRITE_BLOCK(CRestart::SaveAllRestartPoints);
-	WRITE_BLOCK(CRadar::SaveAllRadarBlips);
-	WRITE_BLOCK(CTheZones::SaveAllZones);
-	WRITE_BLOCK(CGangs::SaveAllGangData);
-	WRITE_BLOCK(CTheCarGenerators::SaveAllCarGenerators);
-	WRITE_BLOCK(CParticleObject::SaveParticle);
-	WRITE_BLOCK(cAudioScriptObject::SaveAllAudioScriptObjects);
-	WRITE_BLOCK(CWorld::Players[CWorld::PlayerInFocus].SavePlayerInfo);
-	WRITE_BLOCK(CStats::SaveStats);
-	WRITE_BLOCK(CStreaming::MemoryCardSave);
-	WRITE_BLOCK(CPedType::Save);
+	WriteSaveDataBlock(CPools::SavePedPool);
+	WriteSaveDataBlock(CGarages::Save);
+	WriteSaveDataBlock(CPools::SaveVehiclePool);
+	WriteSaveDataBlock(CPools::SaveObjectPool);
+	WriteSaveDataBlock(ThePaths.Save);
+	WriteSaveDataBlock(CCranes::Save);
+	WriteSaveDataBlock(CPickups::Save);
+	WriteSaveDataBlock(gPhoneInfo.Save);
+	WriteSaveDataBlock(CRestart::SaveAllRestartPoints);
+	WriteSaveDataBlock(CRadar::SaveAllRadarBlips);
+	WriteSaveDataBlock(CTheZones::SaveAllZones);
+	WriteSaveDataBlock(CGangs::SaveAllGangData);
+	WriteSaveDataBlock(CTheCarGenerators::SaveAllCarGenerators);
+	WriteSaveDataBlock(CParticleObject::SaveParticle);
+	WriteSaveDataBlock(cAudioScriptObject::SaveAllAudioScriptObjects);
+	WriteSaveDataBlock(CWorld::Players[CWorld::PlayerInFocus].SavePlayerInfo);
+	WriteSaveDataBlock(CStats::SaveStats);
+	WriteSaveDataBlock(CStreaming::MemoryCardSave);
+	WriteSaveDataBlock(CPedType::Save);
 
 	// Write padding
 	for (int i = 0; i < 4; i++) {
@@ -191,6 +215,115 @@ GenericSave(int file)
 	return true;
 }
 
+bool
+GenericLoad()
+{
+	uint8 *buf;
+	int32 file;
+	uint32 size;
+
+	int32 saveSize;
+	CPad *currPad;
+
+	// Load SimpleVars and Scripts
+	CheckSum = 0;
+	CDate(CompileDateAndTime);
+	CPad::ResetCheats();
+	if (!ReadInSizeofSaveFileBuffer(file, size))
+		return false;
+	size = align4bytes(size);
+	ReadDataFromFile(file, work_buff, size);
+	buf = (work_buff + 0x40);
+	ReadDataFromBufferPointer(buf, saveSize);
+	ReadDataFromBufferPointer(buf, CGame::currLevel);
+	ReadDataFromBufferPointer(buf, TheCamera.GetPosition().x);
+	ReadDataFromBufferPointer(buf, TheCamera.GetPosition().y);
+	ReadDataFromBufferPointer(buf, TheCamera.GetPosition().z);
+	ReadDataFromBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute);
+	ReadDataFromBufferPointer(buf, CClock::ms_nLastClockTick);
+	ReadDataFromBufferPointer(buf, CClock::ms_nGameClockHours);
+	ReadDataFromBufferPointer(buf, CClock::ms_nGameClockMinutes);
+	currPad = CPad::GetPad(0);
+	ReadDataFromBufferPointer(buf, currPad->Mode);
+	ReadDataFromBufferPointer(buf, CTimer::m_snTimeInMilliseconds);
+	ReadDataFromBufferPointer(buf, CTimer::ms_fTimeScale);
+	ReadDataFromBufferPointer(buf, CTimer::ms_fTimeStep);
+	ReadDataFromBufferPointer(buf, CTimer::ms_fTimeStepNonClipped);
+	ReadDataFromBufferPointer(buf, CTimer::m_FrameCounter);
+	ReadDataFromBufferPointer(buf, CTimeStep::ms_fTimeStep);
+	ReadDataFromBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate);
+	ReadDataFromBufferPointer(buf, CTimeStep::ms_fTimeScale);
+	ReadDataFromBufferPointer(buf, CWeather::OldWeatherType);
+	ReadDataFromBufferPointer(buf, CWeather::NewWeatherType);
+	ReadDataFromBufferPointer(buf, CWeather::ForcedWeatherType);
+	ReadDataFromBufferPointer(buf, CWeather::InterpolationValue);
+	ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nSecond);
+	ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nMinute);
+	ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nHour);
+	ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nDay);
+	ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nMonth);
+	ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nYear);
+	ReadDataFromBufferPointer(buf, CWeather::WeatherTypeInList);
+	ReadDataFromBufferPointer(buf, TheCamera.CarZoomIndicator);
+	ReadDataFromBufferPointer(buf, TheCamera.PedZoomIndicator);
+	assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
+	ReadDataFromBlock("Loading Scripts \n", CTheScripts::LoadAllScripts);
+
+	// Load the rest
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading PedPool \n", CPools::LoadPedPool);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Garages \n", CGarages::Load);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Vehicles \n", CPools::LoadVehiclePool);
+	LoadSaveDataBlock();
+	CProjectileInfo::RemoveAllProjectiles();
+	CObject::DeleteAllTempObjects();
+	ReadDataFromBlock("Loading Objects \n", CPools::LoadObjectPool);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Paths \n", ThePaths.Load);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Cranes \n", CCranes::Load);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Pickups \n", CPickups::Load);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Phoneinfo \n", gPhoneInfo.Load);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Restart \n", CRestart::LoadAllRestartPoints);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Radar Blips \n", CRadar::LoadAllRadarBlips);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Zones \n", CTheZones::LoadAllZones);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Gang Data \n", CGangs::LoadAllGangData);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Car Generators \n", CTheCarGenerators::LoadAllCarGenerators);
+	CParticle::ReloadConfig();
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Particles \n", CParticleObject::LoadParticle);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading AudioScript Objects \n", cAudioScriptObject::LoadAllAudioScriptObjects);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Player Info \n", CWorld::Players[CWorld::PlayerInFocus].LoadPlayerInfo);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Stats \n", CStats::LoadStats);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading Streaming Stuff \n", CStreaming::MemoryCardLoad);
+	LoadSaveDataBlock();
+	ReadDataFromBlock("Loading PedType Stuff \n", CPedType::Load);
+
+	DMAudio.SetMusicMasterVolume(CMenuManager::m_PrefsMusicVolume);
+	DMAudio.SetEffectsMasterVolume(CMenuManager::m_PrefsSfxVolume);
+	if (!CloseFile(file)) {
+		PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE;
+		return false;
+	}
+
+	DoGameSpecificStuffAfterSucessLoad();
+	debug("Game successfully loaded \n");
+	return true;
+}
+
 bool
 ReadInSizeofSaveFileBuffer(int32 &file, uint32 &size)
 {
@@ -404,7 +537,7 @@ align4bytes(int32 size)
 
 STARTPATCHES
 	InjectHook(0x58F8D0, GenericSave, PATCH_JUMP);
-	//InjectHook(0x590A00, GenericLoad, PATCH_JUMP);
+	InjectHook(0x590A00, GenericLoad, PATCH_JUMP);
 	InjectHook(0x591910, ReadInSizeofSaveFileBuffer, PATCH_JUMP);
 	InjectHook(0x591990, ReadDataFromFile, PATCH_JUMP);
 	InjectHook(0x591A00, CloseFile, PATCH_JUMP);
diff --git a/src/save/GenericGameStorage.h b/src/save/GenericGameStorage.h
index e22dfc7e..e6fd2e2d 100644
--- a/src/save/GenericGameStorage.h
+++ b/src/save/GenericGameStorage.h
@@ -1,37 +1,43 @@
-#pragma once
-
-#include "PCSave.h"
-
-#define SLOT_COUNT (8)
-
-bool GenericSave(int file);
-bool GenericLoad();
-bool ReadInSizeofSaveFileBuffer(int32 &file, uint32 &size);
-bool ReadDataFromFile(int32 file, uint8 *buf, uint32 size);
-bool CloseFile(int32 file);
-void DoGameSpecificStuffAfterSucessLoad();
-bool CheckSlotDataValid(int32 slot);
-void MakeSpaceForSizeInBufferPointer(uint8 *&presize, uint8 *&buf, uint8 *&postsize);
-void CopySizeAndPreparePointer(uint8 *&buf, uint8 *&postbuf, uint8 *&postbuf2, uint32 &unused, uint32 &size);
-void DoGameSpecificStuffBeforeSave();
-void MakeValidSaveName(int32 slot);
-wchar *GetSavedGameDateAndTime(int32 slot);
-wchar *GetNameOfSavedGame(int32 slot);
-bool CheckDataNotCorrupt(int32 slot, char *name);
-bool RestoreForStartLoad();
-int align4bytes(int32 size);
-
-extern class CDate& CompileDateAndTime;
-
-extern char (&DefaultPCSaveFileName)[260];
-extern char (&ValidSaveName)[260];
-extern char (&LoadFileName)[256];
-extern wchar (&SlotFileName)[SLOT_COUNT][260];
-extern wchar (&SlotSaveDate)[SLOT_COUNT][70];
-extern int &CheckSum;
-extern enum eLevelName &m_LevelToLoad;
-extern int (&Slots)[SLOT_COUNT+1];
-
-extern char SaveFileNameJustSaved[260]; // 8F2570
-
+#pragma once
+
+#include "PCSave.h"
+
+#define SLOT_COUNT (8)
+
+bool GenericSave(int file);
+bool GenericLoad();
+bool ReadInSizeofSaveFileBuffer(int32 &file, uint32 &size);
+bool ReadDataFromFile(int32 file, uint8 *buf, uint32 size);
+bool CloseFile(int32 file);
+void DoGameSpecificStuffAfterSucessLoad();
+bool CheckSlotDataValid(int32 slot);
+void MakeSpaceForSizeInBufferPointer(uint8 *&presize, uint8 *&buf, uint8 *&postsize);
+void CopySizeAndPreparePointer(uint8 *&buf, uint8 *&postbuf, uint8 *&postbuf2, uint32 &unused, uint32 &size);
+void DoGameSpecificStuffBeforeSave();
+void MakeValidSaveName(int32 slot);
+wchar *GetSavedGameDateAndTime(int32 slot);
+wchar *GetNameOfSavedGame(int32 slot);
+bool CheckDataNotCorrupt(int32 slot, char *name);
+bool RestoreForStartLoad();
+int align4bytes(int32 size);
+
+extern class CDate& CompileDateAndTime;
+
+extern char (&DefaultPCSaveFileName)[260];
+extern char (&ValidSaveName)[260];
+extern char (&LoadFileName)[256];
+extern wchar (&SlotFileName)[SLOT_COUNT][260];
+extern wchar (&SlotSaveDate)[SLOT_COUNT][70];
+extern int &CheckSum;
+extern enum eLevelName &m_LevelToLoad;
+extern int (&Slots)[SLOT_COUNT+1];
+
+extern bool &b_FoundRecentSavedGameWantToLoad;
+extern bool &JustLoadedDontFadeInYet;
+extern bool &StillToFadeOut;
+extern uint32 &TimeStartedCountingForFade;
+extern uint32 &TimeToStayFadedBeforeFadeOut;
+
+extern char SaveFileNameJustSaved[260]; // 8F2570
+
 const char TopLineEmptyFile[] = "THIS FILE IS NOT VALID YET";
\ No newline at end of file
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
index 7993426a..ec84e968 100644
--- a/src/skel/win/win.cpp
+++ b/src/skel/win/win.cpp
@@ -1927,7 +1927,7 @@ _WinMain(HINSTANCE instance,
 		* Enter the message processing loop...
 		*/
 
-		while( !RsGlobal.quit && !FrontEndMenuManager.m_bStartGameLoading )
+		while( !RsGlobal.quit && !FrontEndMenuManager.m_bWantToRestart )
 		{
 			if( PeekMessage(&message, nil, 0U, 0U, PM_REMOVE|PM_NOYIELD) )
 			{
@@ -2059,13 +2059,13 @@ _WinMain(HINSTANCE instance,
 						if (wp.showCmd != SW_SHOWMINIMIZED)
 							RsEventHandler(rsFRONTENDIDLE, nil);
 
-						if ( !FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bLoadingSavedGame )
+						if ( !FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bWantToLoad )
 						{
 							gGameState = GS_INIT_PLAYING_GAME;
 							TRACE("gGameState = GS_INIT_PLAYING_GAME;");
 						}
 
-						if ( FrontEndMenuManager.m_bLoadingSavedGame )
+						if ( FrontEndMenuManager.m_bWantToLoad )
 						{
 							InitialiseGame();
 							FrontEndMenuManager.m_bGameNotLoaded = false;
@@ -2128,7 +2128,7 @@ _WinMain(HINSTANCE instance,
 		RwInitialised = FALSE;
 		
 		FrontEndMenuManager.UnloadTextures();
-		if ( !FrontEndMenuManager.m_bStartGameLoading )
+		if ( !FrontEndMenuManager.m_bWantToRestart )
 			break;
 		
 		CPad::ResetCheats();
@@ -2138,13 +2138,13 @@ _WinMain(HINSTANCE instance,
 		
 		CTimer::Stop();
 		
-		if ( FrontEndMenuManager.m_bLoadingSavedGame )
+		if ( FrontEndMenuManager.m_bWantToLoad )
 		{
 			CGame::ShutDownForRestart();
 			CGame::InitialiseWhenRestarting();
 			DMAudio.ChangeMusicMode(MUSICMODE_GAME);
 			LoadSplash(GetLevelSplashScreen(CGame::currLevel));
-			FrontEndMenuManager.m_bLoadingSavedGame = false;
+			FrontEndMenuManager.m_bWantToLoad = false;
 		}
 		else
 		{
@@ -2168,7 +2168,7 @@ _WinMain(HINSTANCE instance,
 		}
 		
 		FrontEndMenuManager.m_bFirstTime = false;
-		FrontEndMenuManager.m_bStartGameLoading = false;
+		FrontEndMenuManager.m_bWantToRestart = false;
 	}
 	
 
diff --git a/src/text/Pager.cpp b/src/text/Pager.cpp
index 9e484c29..5c6b3ee2 100644
--- a/src/text/Pager.cpp
+++ b/src/text/Pager.cpp
@@ -1,194 +1,194 @@
-#include "common.h"
-#include "patcher.h"
-#include "Pager.h"
-#include "Timer.h"
-#include "Messages.h"
-#include "Hud.h"
-#include "Camera.h"
-
-void
-CPager::Init()
-{
-	ClearMessages();
-	m_nNumDisplayLetters = 8;
-}
-
-void
-CPager::Process()
-{
-	if (m_messages[0].m_pText != nil && m_messages[0].m_nCurrentPosition >= (int32)m_messages[0].m_nStringLength) {
-		m_messages[0].m_pText = nil;
-		uint16 i = 0;
-		while (i < NUMPAGERMESSAGES-1) {
-			if (m_messages[i + 1].m_pText == nil) break;
-			m_messages[i] = m_messages[i + 1];
-			i++;
-		}
-		m_messages[i].m_pText = nil;
-		if (m_messages[0].m_pText != nil)
-			CMessages::AddToPreviousBriefArray(
-				m_messages[0].m_pText,
-				m_messages[0].m_nNumber[0],
-				m_messages[0].m_nNumber[1],
-				m_messages[0].m_nNumber[2],
-				m_messages[0].m_nNumber[3],
-				m_messages[0].m_nNumber[4],
-				m_messages[0].m_nNumber[5],
-				0);
-	}
-	Display();
-	if (m_messages[0].m_pText != nil) {
-		if (TheCamera.m_WideScreenOn || !CHud::m_Wants_To_Draw_Hud || CHud::m_BigMessage[0][0] || CHud::m_BigMessage[2][0]) {
-			RestartCurrentMessage();
-		} else {
-			if (CTimer::GetTimeInMilliseconds() > m_messages[0].m_nTimeToChangePosition) {
-				m_messages[0].m_nCurrentPosition++;
-				m_messages[0].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + m_messages[0].m_nSpeedMs;
-			}
-		}
-	}
-}
-
-void
-CPager::Display()
-{
-	wchar outstr1[256];
-	wchar outstr2[260];
-
-	wchar *pText = m_messages[0].m_pText;
-	uint16 i = 0;
-	if (pText != nil) {
-		CMessages::InsertNumberInString(
-			pText,
-			m_messages[0].m_nNumber[0],
-			m_messages[0].m_nNumber[1],
-			m_messages[0].m_nNumber[2],
-			m_messages[0].m_nNumber[3],
-			m_messages[0].m_nNumber[4],
-			m_messages[0].m_nNumber[5],
-			outstr1);
-		for (; i < m_nNumDisplayLetters; i++) {
-			int pos = m_messages[0].m_nCurrentPosition + i;
-			if (pos >= 0) {
-				if (!outstr1[pos]) break;
-
-				outstr2[i] = outstr1[pos];
-			} else {
-				outstr2[i] = ' ';
-			}
-		}
-	}
-	outstr2[i] = '\0';
-	CHud::SetPagerMessage(outstr2);
-}
-
-void
-CPager::AddMessage(wchar *str, uint16 speed, uint16 priority, uint16 a5)
-{
-	uint16 size = CMessages::GetWideStringLength(str);
-	for (int32 i = 0; i < NUMPAGERMESSAGES; i++) {
-		if (m_messages[i].m_pText) {
-			if (m_messages[i].m_nPriority >= priority)
-				continue;
-
-			for (int j = NUMPAGERMESSAGES-1; j > i; j--)
-				m_messages[j] = m_messages[j-1];
-
-		}
-		m_messages[i].m_pText = str;
-		m_messages[i].m_nSpeedMs = speed;
-		m_messages[i].m_nPriority = priority;
-		m_messages[i].field_10 = a5;
-		m_messages[i].m_nCurrentPosition = -(m_nNumDisplayLetters + 10);
-		m_messages[i].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + speed;
-		m_messages[i].m_nStringLength = size;
-		m_messages[i].m_nNumber[0] = -1;
-		m_messages[i].m_nNumber[1] = -1;
-		m_messages[i].m_nNumber[2] = -1;
-		m_messages[i].m_nNumber[3] = -1;
-		m_messages[i].m_nNumber[4] = -1;
-		m_messages[i].m_nNumber[5] = -1;
-
-		if (i == 0)
-			CMessages::AddToPreviousBriefArray(
-				m_messages[0].m_pText,
-				m_messages[0].m_nNumber[0],
-				m_messages[0].m_nNumber[1],
-				m_messages[0].m_nNumber[2],
-				m_messages[0].m_nNumber[3],
-				m_messages[0].m_nNumber[4],
-				m_messages[0].m_nNumber[5],
-				nil);
-			return;
-	}
-}
-
-void
-CPager::AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11)
-{
-	wchar nstr[520];
-
-	CMessages::InsertNumberInString(str, n1, n2, n3, n4, n5, n6, nstr);
-	uint16 size = CMessages::GetWideStringLength(nstr);
-	for (int32 i = 0; i < NUMPAGERMESSAGES; i++) {
-		if (m_messages[i].m_pText) {
-			if (m_messages[i].m_nPriority >= priority)
-				continue;
-
-			for (int j = NUMPAGERMESSAGES-1; j > i; j--)
-				m_messages[j] = m_messages[j - 1];
-
-		}
-		m_messages[i].m_pText = str;
-		m_messages[i].m_nSpeedMs = speed;
-		m_messages[i].m_nPriority = priority;
-		m_messages[i].field_10 = a11;
-		m_messages[i].m_nCurrentPosition = -(m_nNumDisplayLetters + 10);
-		m_messages[i].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + speed;
-		m_messages[i].m_nStringLength = size;
-		m_messages[i].m_nNumber[0] = n1;
-		m_messages[i].m_nNumber[1] = n2;
-		m_messages[i].m_nNumber[2] = n3;
-		m_messages[i].m_nNumber[3] = n4;
-		m_messages[i].m_nNumber[4] = n5;
-		m_messages[i].m_nNumber[5] = n6;
-
-		if (i == 0)
-			CMessages::AddToPreviousBriefArray(
-				m_messages[0].m_pText,
-				m_messages[0].m_nNumber[0],
-				m_messages[0].m_nNumber[1],
-				m_messages[0].m_nNumber[2],
-				m_messages[0].m_nNumber[3],
-				m_messages[0].m_nNumber[4],
-				m_messages[0].m_nNumber[5],
-				nil);
-		return;
-	}
-}
-
-void
-CPager::ClearMessages()
-{
-	for (int32 i = 0; i < NUMPAGERMESSAGES; i++)
-		m_messages[i].m_pText = nil;
-}
-
-void
-CPager::RestartCurrentMessage()
-{
-	if (m_messages[0].m_pText != nil) {
-		m_messages[0].m_nCurrentPosition = -(m_nNumDisplayLetters + 10);
-		m_messages[0].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + m_messages[0].m_nSpeedMs;
-	}
-}
-
-STARTPATCHES
-	InjectHook(0x52B6F0, &CPager::Init, PATCH_JUMP);
-	InjectHook(0x52B740, &CPager::Process, PATCH_JUMP);
-	InjectHook(0x52B890, &CPager::Display, PATCH_JUMP);
-	InjectHook(0x52B940, &CPager::AddMessage, PATCH_JUMP);
-	InjectHook(0x52BB50, &CPager::AddMessageWithNumber, PATCH_JUMP);
-	InjectHook(0x52BE50, &CPager::RestartCurrentMessage, PATCH_JUMP);
-	InjectHook(0x52BE00, &CPager::ClearMessages, PATCH_JUMP);
+#include "common.h"
+#include "patcher.h"
+#include "Pager.h"
+#include "Timer.h"
+#include "Messages.h"
+#include "Hud.h"
+#include "Camera.h"
+
+void
+CPager::Init()
+{
+	ClearMessages();
+	m_nNumDisplayLetters = 8;
+}
+
+void
+CPager::Process()
+{
+	if (m_messages[0].m_pText != nil && m_messages[0].m_nCurrentPosition >= (int32)m_messages[0].m_nStringLength) {
+		m_messages[0].m_pText = nil;
+		uint16 i = 0;
+		while (i < NUMPAGERMESSAGES-1) {
+			if (m_messages[i + 1].m_pText == nil) break;
+			m_messages[i] = m_messages[i + 1];
+			i++;
+		}
+		m_messages[i].m_pText = nil;
+		if (m_messages[0].m_pText != nil)
+			CMessages::AddToPreviousBriefArray(
+				m_messages[0].m_pText,
+				m_messages[0].m_nNumber[0],
+				m_messages[0].m_nNumber[1],
+				m_messages[0].m_nNumber[2],
+				m_messages[0].m_nNumber[3],
+				m_messages[0].m_nNumber[4],
+				m_messages[0].m_nNumber[5],
+				0);
+	}
+	Display();
+	if (m_messages[0].m_pText != nil) {
+		if (TheCamera.m_WideScreenOn || !CHud::m_Wants_To_Draw_Hud || CHud::m_BigMessage[0][0] || CHud::m_BigMessage[2][0]) {
+			RestartCurrentMessage();
+		} else {
+			if (CTimer::GetTimeInMilliseconds() > m_messages[0].m_nTimeToChangePosition) {
+				m_messages[0].m_nCurrentPosition++;
+				m_messages[0].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + m_messages[0].m_nSpeedMs;
+			}
+		}
+	}
+}
+
+void
+CPager::Display()
+{
+	wchar outstr1[256];
+	wchar outstr2[260];
+
+	wchar *pText = m_messages[0].m_pText;
+	uint16 i = 0;
+	if (pText != nil) {
+		CMessages::InsertNumberInString(
+			pText,
+			m_messages[0].m_nNumber[0],
+			m_messages[0].m_nNumber[1],
+			m_messages[0].m_nNumber[2],
+			m_messages[0].m_nNumber[3],
+			m_messages[0].m_nNumber[4],
+			m_messages[0].m_nNumber[5],
+			outstr1);
+		for (; i < m_nNumDisplayLetters; i++) {
+			int pos = m_messages[0].m_nCurrentPosition + i;
+			if (pos >= 0) {
+				if (!outstr1[pos]) break;
+
+				outstr2[i] = outstr1[pos];
+			} else {
+				outstr2[i] = ' ';
+			}
+		}
+	}
+	outstr2[i] = '\0';
+	CHud::SetPagerMessage(outstr2);
+}
+
+void
+CPager::AddMessage(wchar *str, uint16 speed, uint16 priority, uint16 a5)
+{
+	uint16 size = CMessages::GetWideStringLength(str);
+	for (int32 i = 0; i < NUMPAGERMESSAGES; i++) {
+		if (m_messages[i].m_pText) {
+			if (m_messages[i].m_nPriority >= priority)
+				continue;
+
+			for (int j = NUMPAGERMESSAGES-1; j > i; j--)
+				m_messages[j] = m_messages[j-1];
+
+		}
+		m_messages[i].m_pText = str;
+		m_messages[i].m_nSpeedMs = speed;
+		m_messages[i].m_nPriority = priority;
+		m_messages[i].field_10 = a5;
+		m_messages[i].m_nCurrentPosition = -(m_nNumDisplayLetters + 10);
+		m_messages[i].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + speed;
+		m_messages[i].m_nStringLength = size;
+		m_messages[i].m_nNumber[0] = -1;
+		m_messages[i].m_nNumber[1] = -1;
+		m_messages[i].m_nNumber[2] = -1;
+		m_messages[i].m_nNumber[3] = -1;
+		m_messages[i].m_nNumber[4] = -1;
+		m_messages[i].m_nNumber[5] = -1;
+
+		if (i == 0)
+			CMessages::AddToPreviousBriefArray(
+				m_messages[0].m_pText,
+				m_messages[0].m_nNumber[0],
+				m_messages[0].m_nNumber[1],
+				m_messages[0].m_nNumber[2],
+				m_messages[0].m_nNumber[3],
+				m_messages[0].m_nNumber[4],
+				m_messages[0].m_nNumber[5],
+				nil);
+			return;
+	}
+}
+
+void
+CPager::AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11)
+{
+	wchar nstr[520];
+
+	CMessages::InsertNumberInString(str, n1, n2, n3, n4, n5, n6, nstr);
+	uint16 size = CMessages::GetWideStringLength(nstr);
+	for (int32 i = 0; i < NUMPAGERMESSAGES; i++) {
+		if (m_messages[i].m_pText) {
+			if (m_messages[i].m_nPriority >= priority)
+				continue;
+
+			for (int j = NUMPAGERMESSAGES-1; j > i; j--)
+				m_messages[j] = m_messages[j - 1];
+
+		}
+		m_messages[i].m_pText = str;
+		m_messages[i].m_nSpeedMs = speed;
+		m_messages[i].m_nPriority = priority;
+		m_messages[i].field_10 = a11;
+		m_messages[i].m_nCurrentPosition = -(m_nNumDisplayLetters + 10);
+		m_messages[i].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + speed;
+		m_messages[i].m_nStringLength = size;
+		m_messages[i].m_nNumber[0] = n1;
+		m_messages[i].m_nNumber[1] = n2;
+		m_messages[i].m_nNumber[2] = n3;
+		m_messages[i].m_nNumber[3] = n4;
+		m_messages[i].m_nNumber[4] = n5;
+		m_messages[i].m_nNumber[5] = n6;
+
+		if (i == 0)
+			CMessages::AddToPreviousBriefArray(
+				m_messages[0].m_pText,
+				m_messages[0].m_nNumber[0],
+				m_messages[0].m_nNumber[1],
+				m_messages[0].m_nNumber[2],
+				m_messages[0].m_nNumber[3],
+				m_messages[0].m_nNumber[4],
+				m_messages[0].m_nNumber[5],
+				nil);
+		return;
+	}
+}
+
+void
+CPager::ClearMessages()
+{
+	for (int32 i = 0; i < NUMPAGERMESSAGES; i++)
+		m_messages[i].m_pText = nil;
+}
+
+void
+CPager::RestartCurrentMessage()
+{
+	if (m_messages[0].m_pText != nil) {
+		m_messages[0].m_nCurrentPosition = -(m_nNumDisplayLetters + 10);
+		m_messages[0].m_nTimeToChangePosition = CTimer::GetTimeInMilliseconds() + m_messages[0].m_nSpeedMs;
+	}
+}
+
+STARTPATCHES
+	InjectHook(0x52B6F0, &CPager::Init, PATCH_JUMP);
+	InjectHook(0x52B740, &CPager::Process, PATCH_JUMP);
+	InjectHook(0x52B890, &CPager::Display, PATCH_JUMP);
+	InjectHook(0x52B940, &CPager::AddMessage, PATCH_JUMP);
+	InjectHook(0x52BB50, &CPager::AddMessageWithNumber, PATCH_JUMP);
+	InjectHook(0x52BE50, &CPager::RestartCurrentMessage, PATCH_JUMP);
+	InjectHook(0x52BE00, &CPager::ClearMessages, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/text/Pager.h b/src/text/Pager.h
index 1719e726..a628be6f 100644
--- a/src/text/Pager.h
+++ b/src/text/Pager.h
@@ -1,28 +1,28 @@
-#pragma once
-
-struct PagerMessage {
-	wchar *m_pText;
-	uint16 m_nSpeedMs;
-	int16 m_nCurrentPosition;
-	uint16 m_nStringLength;
-	uint16 m_nPriority;
-	uint32 m_nTimeToChangePosition;
-	int16 field_10;
-	int32 m_nNumber[6];
-};
-
-#define NUMPAGERMESSAGES 8
-
-class CPager
-{
-	int16 m_nNumDisplayLetters;
-	PagerMessage m_messages[NUMPAGERMESSAGES];
-public:
-	void Init();
-	void Process();
-	void Display();
-	void AddMessage(wchar*, uint16, uint16, uint16);
-	void AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11);
-	void ClearMessages();
-	void RestartCurrentMessage();
+#pragma once
+
+struct PagerMessage {
+	wchar *m_pText;
+	uint16 m_nSpeedMs;
+	int16 m_nCurrentPosition;
+	uint16 m_nStringLength;
+	uint16 m_nPriority;
+	uint32 m_nTimeToChangePosition;
+	int16 field_10;
+	int32 m_nNumber[6];
+};
+
+#define NUMPAGERMESSAGES 8
+
+class CPager
+{
+	int16 m_nNumDisplayLetters;
+	PagerMessage m_messages[NUMPAGERMESSAGES];
+public:
+	void Init();
+	void Process();
+	void Display();
+	void AddMessage(wchar*, uint16, uint16, uint16);
+	void AddMessageWithNumber(wchar *str, int32 n1, int32 n2, int32 n3, int32 n4, int32 n5, int32 n6, uint16 speed, uint16 priority, uint16 a11);
+	void ClearMessages();
+	void RestartCurrentMessage();
 };
\ No newline at end of file
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index e6b936f6..257c8d33 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -182,17 +182,17 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
 	m_weaponDoorTimerRight = m_weaponDoorTimerLeft;
 
 	if(GetModelIndex() == MI_DODO){
-		RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+		RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
 		CMatrix mat1;
 		mat1.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
 		CMatrix mat2(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
 		mat1.GetPosition() += CVector(mat2.GetPosition().x + 0.1f, 0.0f, mat2.GetPosition().z);
 		mat1.UpdateRW();
 	}else if(GetModelIndex() == MI_MIAMI_SPARROW || GetModelIndex() == MI_MIAMI_RCRAIDER){
-		RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
-		RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
-		RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
-		RpAtomicSetFlags(GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+		RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+		RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
+		RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+		RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
 	}else if(GetModelIndex() == MI_RHINO){
 		bExplosionProof = true;
 		bBulletProof = true;
@@ -253,7 +253,7 @@ CAutomobile::ProcessControl(void)
 
 	ProcessCarAlarm();
 
-	// Scan if this car is committing a crime that the police can see
+	// Scan if this car sees the player committing any crimes
 	if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED &&
 	   m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){
 		switch(GetModelIndex())
@@ -356,7 +356,7 @@ CAutomobile::ProcessControl(void)
 
 			PruneReferences();
 
-			if(m_status == STATUS_PLAYER && CRecordDataForChase::Status != RECORDSTATE_1)
+			if(m_status == STATUS_PLAYER && CRecordDataForChase::IsRecording())
 				DoDriveByShootings();
 		}
 		break;
@@ -667,7 +667,7 @@ CAutomobile::ProcessControl(void)
 		if(!strongGrip1 && !CVehicle::bCheat3)
 			gripCheat = false;
 		float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
-		acceleration /= fForceMultiplier;
+		acceleration /= m_fForceMultiplier;
 
 		// unused
 		if(GetModelIndex() == MI_MIAMI_RCBARON ||
@@ -718,7 +718,7 @@ CAutomobile::ProcessControl(void)
 		else
 			traction = 0.004f;
 		traction *= pHandling->fTractionMultiplier / 4.0f;
-		traction /= fForceMultiplier;
+		traction /= m_fForceMultiplier;
 		if(CVehicle::bCheat3)
 			traction *= 4.0f;
 
@@ -1727,9 +1727,9 @@ CAutomobile::PreRender(void)
 
 		// bright lights
 		if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
-			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + BRIGHTLIGHT_FRONT);
 		if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
-			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + BRIGHTLIGHT_FRONT);
 
 		// Taillights
 
@@ -1798,9 +1798,9 @@ CAutomobile::PreRender(void)
 
 		// bright lights
 		if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
-			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 		if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
-			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 
 		// Light shadows
 		if(!alarmOff){
@@ -1873,9 +1873,9 @@ CAutomobile::PreRender(void)
 							CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
 							CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_FRONT);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_FRONT);
 				}else{
 					// braking
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
@@ -1889,9 +1889,9 @@ CAutomobile::PreRender(void)
 							CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
 							CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 				}
 			}else{
 				if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
@@ -2814,7 +2814,7 @@ CAutomobile::ProcessBuoyancy(void)
 	CVector impulse, point;
 
 	if(mod_Buoyancy.ProcessBuoyancy(this, m_fBuoyancy, &point, &impulse)){
-		m_flagD8 = true;
+		bTouchingWater = true;
 		ApplyMoveForce(impulse);
 		ApplyTurnForce(impulse, point);
 
@@ -2899,7 +2899,7 @@ CAutomobile::ProcessBuoyancy(void)
 		}
 	}else{
 		bIsInWater = false;
-		m_flagD8 = false;
+		bTouchingWater = false;
 
 		static RwRGBA splashCol = {155, 155, 185, 196};
 		static RwRGBA smokeCol = {255, 255, 255, 255};
@@ -3791,7 +3791,7 @@ CAutomobile::BlowUpCar(CEntity *culprit)
 	}
 	ChangeLawEnforcerState(false);
 
-	gFireManager.StartFire(this, culprit, 0.8f, 1);	// TODO
+	gFireManager.StartFire(this, culprit, 0.8f, true);
 	CDarkel::RegisterCarBlownUpByPlayer(this);
 	if(GetModelIndex() == MI_RCBANDIT)
 		CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR_QUICK, GetPosition(), 0);
@@ -4054,7 +4054,7 @@ CAutomobile::HasCarStoppedBecauseOfLight(void)
 			if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nNextRouteNode)
 				break;
 		if(i < curnode->numLinks &&
-		   ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3)	// TODO
+		   ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3)
 			return true;
 	}
 
@@ -4064,7 +4064,7 @@ CAutomobile::HasCarStoppedBecauseOfLight(void)
 			if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nPrevRouteNode)
 				break;
 		if(i < curnode->numLinks &&
-		   ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3)	// TODO
+		   ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3)
 			return true;
 	}
 
diff --git a/src/vehicles/Bike.h b/src/vehicles/Bike.h
new file mode 100644
index 00000000..4e7e5a0e
--- /dev/null
+++ b/src/vehicles/Bike.h
@@ -0,0 +1,15 @@
+#pragma once
+
+// some miami bike leftovers
+
+enum eBikeNodes {
+	BIKE_NODE_NONE,
+	BIKE_CHASSIS,
+	BIKE_FORKS_FRONT,
+	BIKE_FORKS_REAR,
+	BIKE_WHEEL_FRONT,
+	BIKE_WHEEL_REAR,
+	BIKE_MUDGUARD,
+	BIKE_HANDLEBARS,
+	BIKE_NUM_NODES
+};
\ No newline at end of file
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 6d584017..0159d168 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -1,12 +1,25 @@
 #include "common.h"
 #include "patcher.h"
-#include "Boat.h"
+#include "General.h"
+#include "Timecycle.h"
 #include "HandlingMgr.h"
+#include "CarCtrl.h"
 #include "RwHelper.h"
 #include "ModelIndices.h"
+#include "VisibilityPlugins.h"
+#include "DMAudio.h"
+#include "Camera.h"
+#include "Darkel.h"
+#include "Explosion.h"
+#include "Particle.h"
 #include "WaterLevel.h"
-#include "Pools.h"
+#include "Floater.h"
 #include "World.h"
+#include "Pools.h"
+#include "Pad.h"
+#include "Boat.h"
+
+#define INVALID_ORIENTATION (-9999.99f)
 
 float &fShapeLength = *(float*)0x600E78;
 float &fShapeTime   = *(float*)0x600E7C;
@@ -19,10 +32,6 @@ float WAKE_LIFETIME = 400.0f;
 
 CBoat * (&CBoat::apFrameWakeGeneratingBoats)[4] = *(CBoat * (*)[4])*(uintptr*)0x8620E0;
 
-WRAPPER void CBoat::ProcessControl() { EAXJMP(0x53EF10); }
-WRAPPER void CBoat::ProcessControlInputs(uint8) { EAXJMP(0x53EC70); }
-WRAPPER void CBoat::BlowUpCar(CEntity* ent) { EAXJMP(0x541CB0); }
-
 CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
 {
 	CVehicleModelInfo *minfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(mi);
@@ -47,35 +56,31 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
 	m_fGasPedal = 0.0f;
 	m_fBrakePedal = 0.0f;
 
-	field_288 = 0.25f;
-	field_28C = 0.35f;
-	field_290 = 0.7f;
-	field_294 = 0.998f;
-	field_298 = 0.999f;
-	field_29C = 0.85f;
-	field_2A0 = 0.96f;
-	field_2A4 = 0.96f;
+	m_fPropellerZ = 0.25f;
+	m_fPropellerY = 0.35f;
+	m_waterMoveDrag = CVector(0.7f, 0.998f, 0.999f);
+	m_waterTurnDrag = CVector(0.85f, 0.96f, 0.96f);
 	_unk2 = false;
 
-	m_fTurnForceZ = 7.0f;
-	field_2FC = 7.0f;
-	m_vecMoveForce = CVector(0.0f, 0.0f, 0.0f);
+	m_fVolumeUnderWater = 7.0f;
+	m_fPrevVolumeUnderWater = 7.0f;
+	m_vecBuoyancePoint = CVector(0.0f, 0.0f, 0.0f);
 
-	field_300 = 0;
-	m_bBoatFlag1 = true;
-	m_bBoatFlag2 = true;
+	m_nDeltaVolumeUnderWater = 0;
+	bBoatInWater = true;
+	bPropellerInWater = true;
 
 	bIsInWater = true;
 
 	unk1 = 0.0f;
 	m_bIsAnchored = true;
-	field_2C4 = -9999.99f;
-	m_flagD8 = true;
-	field_2CC = 0.0f;
-	field_2D0 = 0;
+	m_fOrientation = INVALID_ORIENTATION;
+	bTouchingWater = true;
+	m_fDamage = 0.0f;
+	m_pSetOnFireEntity = nil;
 	m_nNumWakePoints = 0;
 
-	for (int16 i = 0; i < 32; i++)
+	for (int16 i = 0; i < ARRAY_SIZE(m_afWakePointLifeTime); i++)
 		m_afWakePointLifeTime[i] = 0.0f;
 
 	m_nAmmoInClip = 20;
@@ -94,7 +99,542 @@ CBoat::GetComponentWorldPosition(int32 component, CVector &pos)
 	pos = *RwMatrixGetPos(RwFrameGetLTM(m_aBoatNodes[component]));
 }
 
-RxObjSpace3DVertex KeepWaterOutVertices[4];
+void
+CBoat::ProcessControl(void)
+{
+	if(m_nZoneLevel > LEVEL_NONE && m_nZoneLevel != CCollision::ms_collisionInMemory)
+		return;
+
+	bool onLand = m_fDamageImpulse > 0.0f && m_vecDamageNormal.z > 0.1f;
+
+	PruneWakeTrail();
+
+	int r, g, b;
+	RwRGBA splashColor, jetColor;
+	r = 114.75f*(CTimeCycle::GetAmbientRed() + 0.5f*CTimeCycle::GetDirectionalRed());
+	g = 114.75f*(CTimeCycle::GetAmbientGreen() + 0.5f*CTimeCycle::GetDirectionalGreen());
+	b = 114.75f*(CTimeCycle::GetAmbientBlue() + 0.5f*CTimeCycle::GetDirectionalBlue());
+	r = clamp(r, 0, 255);
+	g = clamp(g, 0, 255);
+	b = clamp(b, 0, 255);
+	splashColor.red = r;
+	splashColor.green = g;
+	splashColor.blue = b;
+	splashColor.alpha = CGeneral::GetRandomNumberInRange(128, 150);
+
+	r = 242.25f*(CTimeCycle::GetAmbientRed() + 0.5f*CTimeCycle::GetDirectionalRed());
+	g = 242.25f*(CTimeCycle::GetAmbientGreen() + 0.5f*CTimeCycle::GetDirectionalGreen());
+	b = 242.25f*(CTimeCycle::GetAmbientBlue() + 0.5f*CTimeCycle::GetDirectionalBlue());
+	r = clamp(r, 0, 255);
+	g = clamp(g, 0, 255);
+	b = clamp(b, 0, 255);
+	jetColor.red = r;
+	jetColor.green = g;
+	jetColor.blue = b;
+	jetColor.alpha = CGeneral::GetRandomNumberInRange(96, 128);
+
+	CGeneral::GetRandomNumber();	// unused
+
+	ProcessCarAlarm();
+
+	switch(m_status){
+	case STATUS_PLAYER:
+		m_bIsAnchored = false;
+		m_fOrientation = INVALID_ORIENTATION;
+		ProcessControlInputs(0);
+		if(GetModelIndex() == MI_PREDATOR)
+			DoFixedMachineGuns();
+		break;
+	case STATUS_SIMPLE:
+		m_bIsAnchored = false;
+		m_fOrientation = INVALID_ORIENTATION;
+		CPhysical::ProcessControl();
+		bBoatInWater = true;
+		bPropellerInWater = true;
+		bIsInWater = true;
+		return;
+	case STATUS_PHYSICS:
+		m_bIsAnchored = false;
+		m_fOrientation = INVALID_ORIENTATION;
+		CCarCtrl::SteerAIBoatWithPhysics(this);
+		break;
+	case STATUS_ABANDONED:
+	case STATUS_WRECKED:
+		bBoatInWater = true;
+		bPropellerInWater = true;
+		bIsInWater = true;
+		m_fSteerAngle = 0.0;
+		bIsHandbrakeOn = false;
+		m_fBrakePedal = 0.5f;
+		m_fGasPedal = 0.0f;
+		if((GetPosition() - CWorld::Players[CWorld::PlayerInFocus].GetPos()).Magnitude() > 150.0f){
+			m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+			m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+			return;
+		}
+		break;
+	}
+
+	float collisionDamage = pHandling->fCollisionDamageMultiplier * m_fDamageImpulse;
+	if(collisionDamage > 25.0f && m_status != STATUS_WRECKED && m_fHealth >= 150.0f){
+		float prevHealth = m_fHealth;
+		if(this == FindPlayerVehicle()){
+			if(bTakeLessDamage)
+				m_fHealth -= (collisionDamage-25.0f)/6.0f;
+			else
+				m_fHealth -= (collisionDamage-25.0f)/2.0f;
+		}else{
+			if(collisionDamage > 60.0f && pDriver)
+				pDriver->Say(SOUND_PED_CAR_COLLISION);
+			if(bTakeLessDamage)
+				m_fHealth -= (collisionDamage-25.0f)/12.0f;
+			else
+				m_fHealth -= (collisionDamage-25.0f)/4.0f;
+		}
+
+		if(m_fHealth <= 0.0f && prevHealth > 0.0f){
+			m_fHealth = 1.0f;
+			m_pSetOnFireEntity = m_pDamageEntity;
+		}
+	}
+
+	// Damage particles
+	if(m_fHealth <= 600.0f && m_status != STATUS_WRECKED &&
+	   Abs(GetPosition().x - TheCamera.GetPosition().x) < 200.0f &&
+	   Abs(GetPosition().y - TheCamera.GetPosition().y) < 200.0f){
+		float speedSq = m_vecMoveSpeed.MagnitudeSqr();
+		CVector smokeDir = 0.8f*m_vecMoveSpeed;
+		CVector smokePos;
+		switch(GetModelIndex()){
+		case MI_SPEEDER:
+			smokePos = CVector(0.4f, -2.4f, 0.8f);
+			smokeDir += 0.05f*GetRight();
+			smokeDir.z += 0.2f*m_vecMoveSpeed.z;
+			break;
+		case MI_REEFER:
+			smokePos = CVector(2.0f, -1.0f, 0.5f);
+			smokeDir += 0.07f*GetRight();
+			break;
+		case MI_PREDATOR:
+		default:
+			smokePos = CVector(-1.5f, -0.5f, 1.2f);
+			smokeDir += -0.08f*GetRight();
+			break;
+		}
+
+		smokePos = GetMatrix() * smokePos;
+
+		// On fire
+		if(m_fHealth < 150.0f){
+			CParticle::AddParticle(PARTICLE_CARFLAME, smokePos,
+				CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(2.25f/200.0f, 0.09f)),
+				nil, 0.9f);
+			CVector smokePos2 = smokePos;
+			smokePos2.x += CGeneral::GetRandomNumberInRange(-2.25f/4.0f, 2.25f/4.0f);
+			smokePos2.y += CGeneral::GetRandomNumberInRange(-2.25f/4.0f, 2.25f/4.0f);
+			smokePos2.z += CGeneral::GetRandomNumberInRange(2.25f/4.0f, 2.25f);
+			CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, smokePos2, CVector(0.0f, 0.0f, 0.0f));
+
+			m_fDamage += CTimer::GetTimeStepInMilliseconds();
+			if(m_fDamage > 5000.0f)
+				BlowUpCar(m_pSetOnFireEntity);
+		}
+
+		if(speedSq < 0.25f && (CTimer::GetFrameCounter() + m_randomSeed) & 1)
+			CParticle::AddParticle(PARTICLE_ENGINE_STEAM, smokePos, smokeDir);
+		if(speedSq < 0.25f && m_fHealth <= 350.0f)
+			CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, smokePos, 1.25f*smokeDir);
+	}
+
+	CPhysical::ProcessControl();
+
+	CVector buoyanceImpulse(0.0f, 0.0f, 0.0f);
+	CVector buoyancePoint(0.0f, 0.0f, 0.0f);
+	if(mod_Buoyancy.ProcessBuoyancy(this, pHandling->fBuoyancy, &buoyancePoint, &buoyanceImpulse)){
+		// Process boat in water
+		if(0.1f * m_fMass * GRAVITY*CTimer::GetTimeStep() < buoyanceImpulse.z){
+			bBoatInWater = true;
+			bIsInWater = true;
+		}else{
+			bBoatInWater = false;
+			bIsInWater = false;
+		}
+
+		m_fVolumeUnderWater = mod_Buoyancy.m_volumeUnderWater;
+		m_vecBuoyancePoint = buoyancePoint;
+		ApplyMoveForce(buoyanceImpulse);
+		if(!onLand)
+			ApplyTurnForce(buoyanceImpulse, buoyancePoint);
+
+		if(!onLand && bBoatInWater && GetUp().z > 0.0f){
+			float impulse;
+			if(m_fGasPedal > 0.05f)
+				impulse = m_vecMoveSpeed.MagnitudeSqr()*pHandling->fSuspensionForceLevel*buoyanceImpulse.z*CTimer::GetTimeStep()*0.5f*m_fGasPedal;
+			else
+				impulse = 0.0f;
+			impulse = min(impulse, GRAVITY*pHandling->fSuspensionDampingLevel*m_fMass*CTimer::GetTimeStep());
+			ApplyMoveForce(impulse*GetUp());
+			ApplyTurnForce(impulse*GetUp(), buoyancePoint - pHandling->fSuspensionBias*GetForward());
+		}
+
+		// Handle boat moving forward
+		if(Abs(m_fGasPedal) > 0.05f || m_vecMoveSpeed.Magnitude() > 0.01f){
+			if(bBoatInWater)
+				AddWakePoint(GetPosition());
+
+			float steerFactor = 1.0f - DotProduct(m_vecMoveSpeed, GetForward());
+			if(m_modelIndex == MI_GHOST)
+				steerFactor = 1.0f - DotProduct(m_vecMoveSpeed, GetForward())*0.3f;
+			if(steerFactor < 0.0f) steerFactor = 0.0f;
+
+			CVector propeller(0.0f, -pHandling->Dimension.y*m_fPropellerY, -pHandling->Dimension.z*m_fPropellerZ);
+			propeller = Multiply3x3(GetMatrix(), propeller);
+			CVector propellerWorld = GetPosition() + propeller;
+
+			float steerSin = Sin(-m_fSteerAngle * steerFactor);
+			float steerCos = Cos(-m_fSteerAngle * steerFactor);
+			float waterLevel;
+			CWaterLevel::GetWaterLevel(propellerWorld, &waterLevel, true);
+			if(propellerWorld.z-0.5f < waterLevel){
+				float propellerDepth = waterLevel - (propellerWorld.z - 0.5f);
+				if(propellerDepth > 1.0f)
+					propellerDepth = 1.0f;
+				else
+					propellerDepth = SQR(propellerDepth);
+				bPropellerInWater = true;
+
+				if(Abs(m_fGasPedal) > 0.05f){
+					CVector forceDir = Multiply3x3(GetMatrix(), CVector(-steerSin, steerCos, -Abs(m_fSteerAngle)));
+					CVector force = propellerDepth * m_fGasPedal * 40.0f * pHandling->Transmission.fEngineAcceleration * pHandling->fMass * forceDir;
+					if(force.z > 0.2f)
+						force.z = SQR(1.2f - force.z) + 0.2f;
+					if(onLand){
+						if(m_fGasPedal < 0.0f){
+							force.x *= 5.0f;
+							force.y *= 5.0f;
+						}
+						if(force.z < 0.0f)
+							force.z = 0.0f;
+						ApplyMoveForce(force * CTimer::GetTimeStep());
+					}else{
+						ApplyMoveForce(force * CTimer::GetTimeStep());
+						ApplyTurnForce(force * CTimer::GetTimeStep(), propeller - pHandling->fTractionBias*GetUp());
+						float rightForce = DotProduct(GetRight(), force);
+						ApplyTurnForce(-rightForce*GetRight() * CTimer::GetTimeStep(), GetUp());
+					}
+
+					// Spray some particles
+					CVector jetDir = -0.04f * force;
+					if(m_fGasPedal > 0.0f){
+						if(m_status == STATUS_PLAYER){
+							bool cameraHack = TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+								TheCamera.WhoIsInControlOfTheCamera == CAMCONTROL_OBBE;
+							CVector sternPos = GetColModel()->boundingBox.min;
+							sternPos.x = 0.0f;
+							sternPos.z = 0.0f;
+							sternPos = Multiply3x3(GetMatrix(), sternPos);
+
+							CVector jetPos = GetPosition() + sternPos;
+							if(cameraHack)
+								jetPos.z = 1.0f;
+							else
+								jetPos.z = 0.0f;
+
+							CVector wakePos = GetPosition() + sternPos;
+							wakePos.z -= 0.65f;
+
+							CVector wakeDir = 0.75f * jetDir;
+
+							CParticle::AddParticle(PARTICLE_BOAT_THRUSTJET, jetPos, jetDir, nil, 0.0f, jetColor);
+							CParticle::AddParticle(PARTICLE_CAR_SPLASH, jetPos, 0.25f * jetDir, nil, 1.0f, splashColor,
+								CGeneral::GetRandomNumberInRange(0, 30),
+								CGeneral::GetRandomNumberInRange(0, 90), 3);
+							if(!cameraHack)
+								CParticle::AddParticle(PARTICLE_BOAT_WAKE, wakePos, wakeDir, nil, 0.0f, jetColor);
+						}else if((CTimer::GetFrameCounter() + m_randomSeed) & 1){
+							jetDir.z = 0.018f;
+							jetDir.x *= 0.01f;
+							jetDir.y *= 0.01f;
+							propellerWorld.z += 1.5f;
+
+							CParticle::AddParticle(PARTICLE_BOAT_SPLASH, propellerWorld, jetDir, nil, 1.5f, jetColor);
+							CParticle::AddParticle(PARTICLE_CAR_SPLASH, propellerWorld, 0.1f * jetDir, nil, 0.5f, splashColor,
+								CGeneral::GetRandomNumberInRange(0, 30),
+								CGeneral::GetRandomNumberInRange(0, 90), 3);
+						}
+					}
+				}else if(!onLand){
+					float force = 50.0f*DotProduct(m_vecMoveSpeed, GetForward());
+					if(force > 10.0f) force = 10.0f;
+					CVector propellerForce = propellerDepth * Multiply3x3(GetMatrix(), force*CVector(-steerSin, 0.0f, 0.0f));
+					ApplyMoveForce(propellerForce * CTimer::GetTimeStep()*0.5f);
+					ApplyTurnForce(propellerForce * CTimer::GetTimeStep()*0.5f, propeller);
+				}
+			}else
+				bPropellerInWater = false;
+		}
+
+		// Slow down or push down boat as it approaches the world limits
+		m_vecMoveSpeed.x = min(m_vecMoveSpeed.x, -(GetPosition().x - 1900.0f)*0.01f);	// east
+		m_vecMoveSpeed.x = max(m_vecMoveSpeed.x, -(GetPosition().x - -1515.0f)*0.01f);	// west
+		m_vecMoveSpeed.y = min(m_vecMoveSpeed.y, -(GetPosition().y - 600.0f)*0.01f);	// north
+		m_vecMoveSpeed.y = max(m_vecMoveSpeed.y, -(GetPosition().y - -1900.0f)*0.01f);	// south
+
+		if(!onLand && bBoatInWater)
+			ApplyWaterResistance();
+
+		// No idea what exactly is going on here besides drag in YZ
+		float fx = Pow(m_waterTurnDrag.x, CTimer::GetTimeStep());
+		float fy = Pow(m_waterTurnDrag.y, CTimer::GetTimeStep());
+		float fz = Pow(m_waterTurnDrag.z, CTimer::GetTimeStep());
+		m_vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix());	// invert - to local space
+		// TODO: figure this out
+		float magic = 1.0f/(1000.0f * SQR(m_vecTurnSpeed.x) + 1.0f) * fx;
+		m_vecTurnSpeed.y *= fy;
+		m_vecTurnSpeed.z *= fz;
+		float forceUp = (magic - 1.0f) * m_vecTurnSpeed.x * m_fTurnMass;
+		m_vecTurnSpeed = Multiply3x3(GetMatrix(), m_vecTurnSpeed);	// back to world
+		CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass);
+		ApplyTurnForce(CVector(0.0f, 0.0f, forceUp), com + GetForward());
+
+		m_nDeltaVolumeUnderWater = (m_fVolumeUnderWater-m_fPrevVolumeUnderWater)*10000;
+
+		// Falling into water
+		if(!onLand && bBoatInWater && GetUp().z > 0.0f && m_nDeltaVolumeUnderWater > 200){
+			DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, m_nDeltaVolumeUnderWater);
+
+			float speedUp = m_vecMoveSpeed.MagnitudeSqr() * m_nDeltaVolumeUnderWater * 0.0004f;
+			if(speedUp + m_vecMoveSpeed.z > pHandling->fBrakeDeceleration)
+				speedUp = pHandling->fBrakeDeceleration - m_vecMoveSpeed.z;
+			if(speedUp < 0.0f) speedUp = 0.0f;
+			float speedFwd = DotProduct(m_vecMoveSpeed, GetForward());
+			speedFwd *= -m_nDeltaVolumeUnderWater * 0.01f * pHandling->fTractionLoss;
+			CVector speed = speedFwd*GetForward() + CVector(0.0f, 0.0f, speedUp);
+			CVector splashImpulse = speed * m_fMass;
+			ApplyMoveForce(splashImpulse);
+			ApplyTurnForce(splashImpulse, buoyancePoint);
+		}
+
+		// Spray particles on sides of boat
+		if(m_nDeltaVolumeUnderWater > 75){
+			float speed = m_vecMoveSpeed.Magnitude();
+			float splash1Size = speed;
+			float splash2Size = m_nDeltaVolumeUnderWater * 0.005f * 0.2f;
+			float front = 0.9f * GetColModel()->boundingBox.max.y;
+			if(splash1Size > 0.75f) splash1Size = 0.75f;
+
+			CVector dir, pos;
+
+			// right
+			dir = -0.5f*m_vecMoveSpeed;
+			dir.z += 0.1f*speed;
+			dir += 0.5f*GetRight()*speed;
+			pos = front*GetForward() + 0.5f*GetRight() + GetPosition() + m_vecBuoyancePoint;
+			CWaterLevel::GetWaterLevel(pos, &pos.z, true);
+			CParticle::AddParticle(PARTICLE_CAR_SPLASH, pos, 0.75f * dir, nil, splash1Size, splashColor,
+				CGeneral::GetRandomNumberInRange(0, 30),
+				CGeneral::GetRandomNumberInRange(0, 90), 1);
+			CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size, jetColor);
+
+			// left
+			dir = -0.5f*m_vecMoveSpeed;
+			dir.z += 0.1f*speed;
+			dir -= 0.5f*GetRight()*speed;
+			pos = front*GetForward() - 0.5f*GetRight() + GetPosition() + m_vecBuoyancePoint;
+			CWaterLevel::GetWaterLevel(pos, &pos.z, true);
+			CParticle::AddParticle(PARTICLE_CAR_SPLASH, pos, 0.75f * dir, nil, splash1Size, splashColor,
+				CGeneral::GetRandomNumberInRange(0, 30),
+				CGeneral::GetRandomNumberInRange(0, 90), 1);
+			CParticle::AddParticle(PARTICLE_BOAT_SPLASH, pos, dir, nil, splash2Size, jetColor);
+		}
+
+		m_fPrevVolumeUnderWater = m_fVolumeUnderWater;
+	}else{
+		bBoatInWater = false;
+		bIsInWater = false;
+	}
+
+	if(m_bIsAnchored){
+		m_vecMoveSpeed.x = 0.0f;
+		m_vecMoveSpeed.y = 0.0f;
+
+		if(m_fOrientation == INVALID_ORIENTATION){
+			m_fOrientation = GetForward().Heading();
+		}else{
+			// is this some inlined CPlaceable method?
+			CVector pos = GetPosition();
+			GetMatrix().RotateZ(m_fOrientation - GetForward().Heading());
+			GetPosition() = pos;
+		}
+	}
+
+	ProcessDelayedExplosion();
+}
+
+void
+CBoat::ProcessControlInputs(uint8 pad)
+{
+	m_nPadID = pad;
+	if(m_nPadID > 3)
+		m_nPadID = 3;
+
+	m_fBrake += (CPad::GetPad(pad)->GetBrake()/255.0f - m_fBrake)*0.1f;
+	m_fBrake = clamp(m_fBrake, 0.0f, 1.0f);
+
+	if(m_fBrake < 0.05f){
+		m_fBrake = 0.0f;
+		m_fAccelerate += (CPad::GetPad(pad)->GetAccelerate()/255.0f - m_fAccelerate)*0.1f;
+		m_fAccelerate = clamp(m_fAccelerate, 0.0f, 1.0f);
+	}else
+		m_fAccelerate = -m_fBrake*0.2f;
+
+	m_fSteeringLeftRight += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteeringLeftRight)*0.2f;
+	m_fSteeringLeftRight = clamp(m_fSteeringLeftRight, -1.0f, 1.0f);
+
+	float steeringSq = m_fSteeringLeftRight < 0.0f ? -SQR(m_fSteeringLeftRight) : SQR(m_fSteeringLeftRight);
+	m_fSteerAngle = pHandling->fSteeringLock * DEGTORAD(steeringSq);
+	m_fGasPedal = m_fAccelerate;
+}
+
+void
+CBoat::ApplyWaterResistance(void)
+{
+	float fwdSpeed = DotProduct(GetMoveSpeed(), GetForward());
+	// TODO: figure out how this works
+	float magic = (SQR(fwdSpeed) + 0.05f) * (0.001f * SQR(m_fVolumeUnderWater) * m_fMass) + 1.0f;
+	magic = Abs(magic);
+	// FRAMETIME
+	float fx = Pow(m_waterMoveDrag.x/magic, 0.5f*CTimer::GetTimeStep());
+	float fy = Pow(m_waterMoveDrag.y/magic, 0.5f*CTimer::GetTimeStep());
+	float fz = Pow(m_waterMoveDrag.z/magic, 0.5f*CTimer::GetTimeStep());
+
+	m_vecMoveSpeed = Multiply3x3(m_vecMoveSpeed, GetMatrix());	// invert - to local space
+	m_vecMoveSpeed.x *= fx;
+	m_vecMoveSpeed.y *= fy;
+	m_vecMoveSpeed.z *= fz;
+	float force = (fy - 1.0f) * m_vecMoveSpeed.y * m_fMass;
+	m_vecMoveSpeed = Multiply3x3(GetMatrix(), m_vecMoveSpeed);	// back to world
+
+	ApplyTurnForce(force*GetForward(), -GetUp());
+
+	if(m_vecMoveSpeed.z > 0.0f)
+		m_vecMoveSpeed.z *= fz;
+	else
+		m_vecMoveSpeed.z *= (1.0f - fz)*0.5f + fz;
+}
+
+RwObject*
+GetBoatAtomicObjectCB(RwObject *object, void *data)
+{
+	RpAtomic *atomic = (RpAtomic*)object;
+	assert(RwObjectGetType(object) == rpATOMIC);
+	if(RpAtomicGetFlags(atomic) & rpATOMICRENDER)
+		*(RpAtomic**)data = atomic;
+	return object;
+
+	
+}
+
+void
+CBoat::BlowUpCar(CEntity *culprit)
+{
+	RpAtomic *atomic;
+	RwFrame *frame;
+	RwMatrix *matrix;
+	CObject *obj;
+
+	if(!bCanBeDamaged)
+		return;
+
+	// explosion pushes vehicle up
+	m_vecMoveSpeed.z += 0.13f;
+	m_status = STATUS_WRECKED;
+	bRenderScorched = true;
+
+	m_fHealth = 0.0;
+	m_nBombTimer = 0;
+	TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
+
+	if(this == FindPlayerVehicle())
+		FindPlayerPed()->m_fHealth = 0.0f;	// kill player
+	if(pDriver){
+		CDarkel::RegisterKillByPlayer(pDriver, WEAPONTYPE_EXPLOSION);
+		pDriver->SetDead();
+		pDriver->FlagToDestroyWhenNextProcessed();
+	}
+
+	bEngineOn = false;
+	bLightsOn = false;
+	ChangeLawEnforcerState(false);
+
+	CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR, GetPosition(), 0);
+	if(m_aBoatNodes[BOAT_MOVING] == nil)
+		return;
+
+	// much like CAutomobile::SpawnFlyingComponent from here on
+
+	atomic = nil;
+	RwFrameForAllObjects(m_aBoatNodes[BOAT_MOVING], GetBoatAtomicObjectCB, &atomic);
+	if(atomic == nil)
+		return;
+
+	obj = new CObject();
+	if(obj == nil)
+		return;
+
+	obj->SetModelIndexNoCreate(MI_CAR_WHEEL);
+
+	// object needs base model
+	obj->RefModelInfo(GetModelIndex());
+
+	// create new atomic
+	matrix = RwFrameGetLTM(m_aBoatNodes[BOAT_MOVING]);
+	frame = RwFrameCreate();
+	atomic = RpAtomicClone(atomic);
+	*RwFrameGetMatrix(frame) = *matrix;
+	RpAtomicSetFrame(atomic, frame);
+	CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+	obj->AttachToRwObject((RwObject*)atomic);
+
+	// init object
+	obj->m_fMass = 10.0f;
+	obj->m_fTurnMass = 25.0f;
+	obj->m_fAirResistance = 0.99f;
+	obj->m_fElasticity = 0.1f;
+	obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f;
+	obj->ObjectCreatedBy = TEMP_OBJECT;
+	obj->bIsStatic = false;
+	obj->bIsPickup = false;
+
+	// life time
+	CObject::nNoTempObjects++;
+	obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000;
+
+	obj->m_vecMoveSpeed = m_vecMoveSpeed;
+	if(GetUp().z > 0.0f)
+		obj->m_vecMoveSpeed.z = 0.3f;
+	else
+		obj->m_vecMoveSpeed.z = 0.0f;
+
+	obj->m_vecTurnSpeed = m_vecTurnSpeed*2.0f;
+	obj->m_vecTurnSpeed.x = 0.5f;
+
+	// push component away from boat
+	CVector dist = obj->GetPosition() - GetPosition();
+	dist.Normalise();
+	if(GetUp().z > 0.0f)
+		dist += GetUp();
+	obj->GetPosition() += GetUp();
+
+	CWorld::Add(obj);
+
+	atomic = nil;
+	RwFrameForAllObjects(m_aBoatNodes[BOAT_MOVING], GetBoatAtomicObjectCB, &atomic);
+	if(atomic)
+		RpAtomicSetFlags(atomic, 0);
+}
+
+RwIm3DVertex KeepWaterOutVertices[4];
 RwImVertexIndex KeepWaterOutIndices[6];
 
 void
@@ -102,8 +642,8 @@ CBoat::Render()
 {
 	CMatrix matrix;
 
-	if (m_aBoatNodes[1] != nil) {
-		matrix.Attach(&m_aBoatNodes[1]->modelling);
+	if (m_aBoatNodes[BOAT_MOVING] != nil) {
+		matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_MOVING]));
 
 		CVector pos = matrix.GetPosition();
 		matrix.SetRotateZ(m_fMovingHiRotation);
@@ -111,7 +651,7 @@ CBoat::Render()
 
 		matrix.UpdateRW();
 		if (CVehicle::bWheelsOnlyCheat) {
-			RpAtomicRenderMacro((RpAtomic*)GetFirstObject(m_aBoatNodes[1]));
+			RpAtomicRender((RpAtomic*)GetFirstObject(m_aBoatNodes[BOAT_MOVING]));
 		}
 	}
 	m_fMovingHiRotation += 0.05f;
@@ -130,47 +670,23 @@ CBoat::Render()
 	KeepWaterOutIndices[5] = 3;
 	switch (GetModelIndex()) {
 	case MI_SPEEDER:
-		KeepWaterOutVertices[0].objVertex.x = -1.15f;
-		KeepWaterOutVertices[0].objVertex.y = 3.61f;
-		KeepWaterOutVertices[0].objVertex.z = 1.03f;
-		KeepWaterOutVertices[1].objVertex.x = 1.15f;
-		KeepWaterOutVertices[1].objVertex.y = 3.61f;
-		KeepWaterOutVertices[1].objVertex.z = 1.03f;
-		KeepWaterOutVertices[2].objVertex.x = -1.15f;
-		KeepWaterOutVertices[2].objVertex.y = 0.06f;
-		KeepWaterOutVertices[2].objVertex.z = 1.03f;
-		KeepWaterOutVertices[3].objVertex.x = 1.15f;
-		KeepWaterOutVertices[3].objVertex.y = 0.06f;
-		KeepWaterOutVertices[3].objVertex.z = 1.03f;
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.15f, 3.61f, 1.03f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[1],  1.15f, 3.61f, 1.03f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.15f, 0.06f, 1.03f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[3],  1.15f, 0.06f, 1.03f);
 		break;
 	case MI_REEFER:
-		KeepWaterOutVertices[2].objVertex.x = -1.9f;
-		KeepWaterOutVertices[2].objVertex.y = 2.83f;
-		KeepWaterOutVertices[2].objVertex.z = 1.0f;
-		KeepWaterOutVertices[3].objVertex.x = 1.9f;
-		KeepWaterOutVertices[3].objVertex.y = 2.83f;
-		KeepWaterOutVertices[3].objVertex.z = 1.0f;
-		KeepWaterOutVertices[0].objVertex.x = -1.66f;
-		KeepWaterOutVertices[0].objVertex.y = -4.48f;
-		KeepWaterOutVertices[0].objVertex.z = 0.83f;
-		KeepWaterOutVertices[1].objVertex.x = 1.66f;
-		KeepWaterOutVertices[1].objVertex.y = -4.48f;
-		KeepWaterOutVertices[1].objVertex.z = 0.83f;
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.9f,   2.83f, 1.0f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[1],  1.9f,   2.83f, 1.0f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.66f, -4.48f, 0.83f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[3],  1.66f, -4.48f, 0.83f);
 		break;
 	case MI_PREDATOR:
 	default:
-		KeepWaterOutVertices[0].objVertex.x = -1.45f;
-		KeepWaterOutVertices[0].objVertex.y = 1.9f;
-		KeepWaterOutVertices[0].objVertex.z = 0.96f;
-		KeepWaterOutVertices[1].objVertex.x = 1.45f;
-		KeepWaterOutVertices[1].objVertex.y = 1.9f;
-		KeepWaterOutVertices[1].objVertex.z = 0.96f;
-		KeepWaterOutVertices[2].objVertex.x = -1.45f;
-		KeepWaterOutVertices[2].objVertex.y = -3.75f;
-		KeepWaterOutVertices[2].objVertex.z = 0.96f;
-		KeepWaterOutVertices[3].objVertex.x = 1.45f;
-		KeepWaterOutVertices[3].objVertex.y = -3.75f;
-		KeepWaterOutVertices[3].objVertex.z = 0.96f;
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[0], -1.45f,   1.9f, 0.96f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[1],  1.45f,   1.9f, 0.96f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[2], -1.45f, -3.75f, 0.96f);
+		RwIm3DVertexSetPos(&KeepWaterOutVertices[3],  1.45f, -3.75f, 0.96f);
 		break;
 	}
 	KeepWaterOutVertices[0].u = 0.0f;
@@ -258,10 +774,9 @@ CBoat::IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat)
 void
 CBoat::SetupModelNodes()
 {
-	m_aBoatNodes[0] = nil;
-	m_aBoatNodes[1] = nil;
-	m_aBoatNodes[2] = nil;
-	m_aBoatNodes[3] = nil;
+	int i;
+	for(i = 0; i < ARRAY_SIZE(m_aBoatNodes); i++)
+		m_aBoatNodes[i] = nil;
 	CClumpModelInfo::FillFrameArray(GetClump(), m_aBoatNodes);
 }
 
@@ -299,6 +814,43 @@ CBoat::FillBoatList()
 	}
 }
 
+void
+CBoat::PruneWakeTrail(void)
+{
+	int i;
+
+	for(i = 0; i < ARRAY_SIZE(m_afWakePointLifeTime); i++){
+		if(m_afWakePointLifeTime[i] <= 0.0f)
+			break;
+		if(m_afWakePointLifeTime[i] <= CTimer::GetTimeStep()){
+			m_afWakePointLifeTime[i] = 0.0f;
+			break;
+		}
+		m_afWakePointLifeTime[i] -= CTimer::GetTimeStep();
+	}
+	m_nNumWakePoints = i;
+}
+
+void
+CBoat::AddWakePoint(CVector point)
+{
+	int i;
+	if(m_afWakePointLifeTime[0] > 0.0f){
+		if((CVector2D(GetPosition()) - m_avec2dWakePoints[0]).MagnitudeSqr() < SQR(1.0f)){
+			for(i = min(m_nNumWakePoints, ARRAY_SIZE(m_afWakePointLifeTime)-1); i != 0; i--){
+				m_avec2dWakePoints[i] = m_avec2dWakePoints[i-1];
+				m_afWakePointLifeTime[i] = m_afWakePointLifeTime[i-1];
+			}
+			m_avec2dWakePoints[0] = point;
+			m_afWakePointLifeTime[0] = 400.0f;
+		}
+	}else{
+		m_avec2dWakePoints[0] = point;
+		m_afWakePointLifeTime[0] = 400.0f;
+		m_nNumWakePoints = 1;
+	}
+}
+
 #include <new>
 
 class CBoat_ : public CBoat
@@ -315,4 +867,7 @@ STARTPATCHES
 	InjectHook(0x542370, CBoat::IsSectorAffectedByWake, PATCH_JUMP);
 	InjectHook(0x5424A0, CBoat::IsVertexAffectedByWake, PATCH_JUMP);
 	InjectHook(0x542250, CBoat::FillBoatList, PATCH_JUMP);
+	InjectHook(0x542140, &CBoat::AddWakePoint, PATCH_JUMP);
+	InjectHook(0x5420D0, &CBoat::PruneWakeTrail, PATCH_JUMP);
+	InjectHook(0x541A30, &CBoat::ApplyWaterResistance, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h
index d3a2ac13..f4c6a747 100644
--- a/src/vehicles/Boat.h
+++ b/src/vehicles/Boat.h
@@ -2,47 +2,41 @@
 
 #include "Vehicle.h"
 
+enum eBoatNodes
+{
+	BOAT_MOVING = 1,
+	BOAT_RUDDER,
+	BOAT_WINDSCREEN
+};
+
 class CBoat : public CVehicle
 {
 public:
 	// 0x288
-	float field_288;
-	float field_28C;
-	float field_290;
-	float field_294;
-	float field_298;
-	float field_29C;
-	float field_2A0;
-	float field_2A4;
+	float m_fPropellerZ;
+	float m_fPropellerY;
+	CVector m_waterMoveDrag;
+	CVector m_waterTurnDrag;
 	float m_fMovingHiRotation;
 	int32 _unk0;
 	RwFrame *m_aBoatNodes[4];
-	uint8 m_bBoatFlag1 : 1;
-	uint8 m_bBoatFlag2 : 1;
-	uint8 m_bBoatFlag3 : 1;
-	uint8 m_bBoatFlag4 : 1;
-	uint8 m_bBoatFlag5 : 1;
-	uint8 m_bBoatFlag6 : 1;
-	uint8 m_bBoatFlag7 : 1;
-	uint8 m_bBoatFlag8 : 1;
+	uint8 bBoatInWater : 1;
+	uint8 bPropellerInWater : 1;
 	bool m_bIsAnchored;
-	char _pad0[2];
-	float field_2C4;
+	float m_fOrientation;
 	int32 _unk1;
-	float field_2CC;
-	CEntity *field_2D0;
+	float m_fDamage;
+	CEntity *m_pSetOnFireEntity;
 	bool _unk2;
-	char _pad1[3];
 	float m_fAccelerate;
 	float m_fBrake;
 	float m_fSteeringLeftRight;
 	uint8 m_nPadID;
-	char _pad2[3];
 	int32 _unk3;
-	float m_fTurnForceZ;
-	CVector m_vecMoveForce;
-	float field_2FC;
-	uint16 field_300;
+	float m_fVolumeUnderWater;
+	CVector m_vecBuoyancePoint;
+	float m_fPrevVolumeUnderWater;
+	int16 m_nDeltaVolumeUnderWater;
 	uint16 m_nNumWakePoints;
 	CVector2D m_avec2dWakePoints[32];
 	float m_afWakePointLifeTime[32];
@@ -59,7 +53,10 @@ public:
 	virtual bool IsComponentPresent(int32 component) { return true; }
 	virtual void BlowUpCar(CEntity *ent);
 	
+	void ApplyWaterResistance(void);
 	void SetupModelNodes();
+	void PruneWakeTrail(void);
+	void AddWakePoint(CVector point);
 
 	static CBoat *(&apFrameWakeGeneratingBoats)[4];
 	
diff --git a/src/control/CarGen.cpp b/src/vehicles/CarGen.cpp
similarity index 75%
rename from src/control/CarGen.cpp
rename to src/vehicles/CarGen.cpp
index 49a96f50..c35005a1 100644
--- a/src/control/CarGen.cpp
+++ b/src/vehicles/CarGen.cpp
@@ -14,11 +14,11 @@
 #include "Vehicle.h"
 #include "World.h"
 
-uint8 &CTheCarGenerators::ProcessCounter = *(uint8*)0x95CDAF;
-uint32 &CTheCarGenerators::NumOfCarGenerators = *(uint32*)0x8E2C1C;
-CCarGenerator (&CTheCarGenerators::CarGeneratorArray)[NUM_CARGENS] = *(CCarGenerator(*)[NUM_CARGENS])*(uintptr*)0x87CB18;
-uint8 &CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter = *(uint8*)0x95CDC6;
-uint32 &CTheCarGenerators::CurrentActiveCount = *(uint32*)0x8F2C5C;
+uint8 CTheCarGenerators::ProcessCounter;
+uint32 CTheCarGenerators::NumOfCarGenerators;
+CCarGenerator CTheCarGenerators::CarGeneratorArray[NUM_CARGENS];
+uint8 CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter;
+uint32 CTheCarGenerators::CurrentActiveCount;
 
 void CCarGenerator::SwitchOff()
 {
@@ -187,62 +187,9 @@ bool CCarGenerator::CheckIfWithinRangeOfAnyPlayer()
 	return DotProduct2D(direction, FindPlayerSpeed()) <= 0;
 }
 
-void CCarGenerator::Save(uint8 *&buffer)
-{
-	WriteSaveBuf(buffer, m_nModelIndex);
-	WriteSaveBuf(buffer, m_vecPos);
-	WriteSaveBuf(buffer, m_fAngle);
-	WriteSaveBuf(buffer, m_nColor1);
-	WriteSaveBuf(buffer, m_nColor2);
-	WriteSaveBuf(buffer, m_bForceSpawn);
-	WriteSaveBuf(buffer, m_nAlarm);
-	WriteSaveBuf(buffer, m_nDoorlock);
-	WriteSaveBuf(buffer, (uint8)0);
-	WriteSaveBuf(buffer, m_nMinDelay);
-	WriteSaveBuf(buffer, m_nMaxDelay);
-	WriteSaveBuf(buffer, m_nTimer);
-	WriteSaveBuf(buffer, m_nVehicleHandle);
-	WriteSaveBuf(buffer, m_nUsesRemaining);
-	WriteSaveBuf(buffer, m_bIsBlocking);
-	WriteSaveBuf(buffer, (uint8)0);
-	WriteSaveBuf(buffer, m_vecInf);
-	WriteSaveBuf(buffer, m_vecSup);
-	WriteSaveBuf(buffer, m_fSize);
-
-	// or
-	//WriteSaveBuf(buffer, *this);
-
-}
-
-void CCarGenerator::Load(uint8 *&buffer)
-{
-	m_nModelIndex = ReadSaveBuf<uint32>(buffer);
-	m_vecPos = ReadSaveBuf<CVector>(buffer);
-	m_fAngle = ReadSaveBuf<float>(buffer);
-	m_nColor1 = ReadSaveBuf<int16>(buffer);
-	m_nColor2 = ReadSaveBuf<int16>(buffer);
-	m_bForceSpawn = ReadSaveBuf<uint8>(buffer);
-	m_nAlarm = ReadSaveBuf<uint8>(buffer);
-	m_nDoorlock = ReadSaveBuf<uint8>(buffer);
-	ReadSaveBuf<uint8>(buffer);
-	m_nMinDelay = ReadSaveBuf<uint16>(buffer);
-	m_nMaxDelay = ReadSaveBuf<uint16>(buffer);
-	m_nTimer = ReadSaveBuf<uint32>(buffer);
-	m_nVehicleHandle = ReadSaveBuf<int32>(buffer);
-	m_nUsesRemaining = ReadSaveBuf<uint16>(buffer);
-	m_bIsBlocking = ReadSaveBuf<bool>(buffer);
-	ReadSaveBuf<uint8>(buffer);
-	m_vecInf = ReadSaveBuf<CVector>(buffer);
-	m_vecSup = ReadSaveBuf<CVector>(buffer);
-	m_fSize = ReadSaveBuf<float>(buffer);
-
-	// or
-	//*this = ReadSaveBuf<CCarGenerator>(buffer);
-}
-
 void CTheCarGenerators::Process()
 {
-	if (FindPlayerTrain() || CCutsceneMgr::IsRunning())
+	if (FindPlayerTrain() || CCutsceneMgr::IsCutsceneProcessing())
 		return;
 	if (++CTheCarGenerators::ProcessCounter == 4)
 		CTheCarGenerators::ProcessCounter = 0;
@@ -268,39 +215,38 @@ void CTheCarGenerators::Init()
 
 void CTheCarGenerators::SaveAllCarGenerators(uint8 *buffer, uint32 *size)
 {
-	*size = 20 + sizeof(CarGeneratorArray) + SAVE_HEADER_SIZE;
+	const uint32 nGeneralDataSize = sizeof(NumOfCarGenerators) + sizeof(CurrentActiveCount) + sizeof(ProcessCounter) + sizeof(GenerateEvenIfPlayerIsCloseCounter) + sizeof(int16);
+	*size = sizeof(int) + nGeneralDataSize + sizeof(uint32) + sizeof(CarGeneratorArray) + SAVE_HEADER_SIZE;
 INITSAVEBUF
 	WriteSaveHeader(buffer, 'C','G','N','\0', *size - SAVE_HEADER_SIZE);
 
-	WriteSaveBuf(buffer, 12); /* what is this? */
+	WriteSaveBuf(buffer, nGeneralDataSize);
 	WriteSaveBuf(buffer, NumOfCarGenerators);
 	WriteSaveBuf(buffer, CurrentActiveCount);
 	WriteSaveBuf(buffer, ProcessCounter);
 	WriteSaveBuf(buffer, GenerateEvenIfPlayerIsCloseCounter);
-	WriteSaveBuf(buffer, (int16)0);
+	WriteSaveBuf(buffer, (int16)0); // alignment
 	WriteSaveBuf(buffer, sizeof(CarGeneratorArray));
-	for (int i = 0; i < NUM_CARGENS; i++){
-		CarGeneratorArray[i].Save(buffer);
-	}
+	for (int i = 0; i < NUM_CARGENS; i++)
+		WriteSaveBuf(buffer, CarGeneratorArray[i]);
 VALIDATESAVEBUF(*size)
 }
 
 void CTheCarGenerators::LoadAllCarGenerators(uint8* buffer, uint32 size)
 {
+	const int32 nGeneralDataSize = sizeof(NumOfCarGenerators) + sizeof(CurrentActiveCount) + sizeof(ProcessCounter) + sizeof(GenerateEvenIfPlayerIsCloseCounter) + sizeof(int16);
 	Init();
 INITSAVEBUF
-	assert(size == 20 + sizeof(CarGeneratorArray) + SAVE_HEADER_SIZE);
 	CheckSaveHeader(buffer, 'C','G','N','\0', size - SAVE_HEADER_SIZE);
-	ReadSaveBuf<uint32>(buffer);
+	assert(ReadSaveBuf<uint32>(buffer) == nGeneralDataSize);
 	NumOfCarGenerators = ReadSaveBuf<uint32>(buffer);
 	CurrentActiveCount = ReadSaveBuf<uint32>(buffer);
 	ProcessCounter = ReadSaveBuf<uint8>(buffer);
 	GenerateEvenIfPlayerIsCloseCounter = ReadSaveBuf<uint8>(buffer);
-	ReadSaveBuf<int16>(buffer);
+	ReadSaveBuf<int16>(buffer); // alignment
 	assert(ReadSaveBuf<uint32>(buffer) == sizeof(CarGeneratorArray));
-	for (int i = 0; i < NUM_CARGENS; i++) {
-		CarGeneratorArray[i].Load(buffer);
-	}
+	for (int i = 0; i < NUM_CARGENS; i++) 
+		CarGeneratorArray[i] = ReadSaveBuf<CCarGenerator>(buffer);
 VALIDATESAVEBUF(size)
 }
 
diff --git a/src/control/CarGen.h b/src/vehicles/CarGen.h
similarity index 83%
rename from src/control/CarGen.h
rename to src/vehicles/CarGen.h
index 75acdd56..9d645318 100644
--- a/src/control/CarGen.h
+++ b/src/vehicles/CarGen.h
@@ -34,19 +34,17 @@ public:
 	void Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
 	bool CheckForBlockage();
 	bool CheckIfWithinRangeOfAnyPlayer();
-	void Save(uint8*&);
-	void Load(uint8*&);
 	void SetUsesRemaining(uint16 uses) { m_nUsesRemaining = uses; }
 };
 
 class CTheCarGenerators
 {
 public:
-	static uint8 &ProcessCounter;
-	static uint32 &NumOfCarGenerators;
-	static CCarGenerator (&CarGeneratorArray)[NUM_CARGENS];
-	static uint8 &GenerateEvenIfPlayerIsCloseCounter;
-	static uint32 &CurrentActiveCount;
+	static uint8 ProcessCounter;
+	static uint32 NumOfCarGenerators;
+	static CCarGenerator CarGeneratorArray[NUM_CARGENS];
+	static uint8 GenerateEvenIfPlayerIsCloseCounter;
+	static uint32 CurrentActiveCount;
 
 	static void Process();
 	static int32 CreateCarGenerator(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
diff --git a/src/vehicles/Cranes.cpp b/src/vehicles/Cranes.cpp
new file mode 100644
index 00000000..dbc3c340
--- /dev/null
+++ b/src/vehicles/Cranes.cpp
@@ -0,0 +1,671 @@
+#include "common.h"
+#include "patcher.h"
+#include "Cranes.h"
+
+#include "Camera.h"
+#include "DMAudio.h"
+#include "Garages.h"
+#include "General.h"
+#include "Entity.h"
+#include "ModelIndices.h"
+#include "Replay.h"
+#include "Object.h"
+#include "World.h"
+
+#define MAX_DISTANCE_TO_FIND_CRANE (10.0f)
+#define CRANE_UPDATE_RADIUS (300.0f)
+#define CRANE_MOVEMENT_PROCESSING_RADIUS (150.0f)
+#define CRUSHER_Z (-0.951f)
+#define MILITARY_Z (10.7862f)
+#define DISTANCE_FROM_PLAYER_TO_REMOVE_VEHICLE (5.0f)
+#define DISTANCE_FROM_HOOK_TO_VEHICLE_TO_COLLECT (0.5f)
+#define CAR_REWARD_MILITARY_CRANE (1500)
+#define CAR_MOVING_SPEED_THRESHOLD (0.01f)
+#define CRANE_SLOWDOWN_MULTIPLIER (0.3f)
+
+#define OSCILLATION_SPEED (0.002f)
+#define CAR_ROTATION_SPEED (0.0035f)
+#define CRANE_MOVEMENT_SPEED (0.001f)
+#define HOOK_ANGLE_MOVEMENT_SPEED (0.004f)
+#define HOOK_OFFSET_MOVEMENT_SPEED (0.1f)
+#define HOOK_HEIGHT_MOVEMENT_SPEED (0.06f)
+
+#define MESSAGE_SHOW_DURATION (4000)
+
+#define MAX_DISTANCE (99999.9f)
+#define MIN_VALID_POSITION (-10000.0f)
+#define DEFAULT_OFFSET (20.0f)
+
+uint32 TimerForCamInterpolation;
+
+uint32 CCranes::CarsCollectedMilitaryCrane;
+int32 CCranes::NumCranes;
+CCrane CCranes::aCranes[NUM_CRANES];
+
+void CCranes::InitCranes(void) 
+{
+	CarsCollectedMilitaryCrane = 0;
+	NumCranes = 0;
+	for (int i = 0; i < NUMSECTORS_X; i++) {
+		for (int j = 0; j < NUMSECTORS_Y; j++) {
+			for (CPtrNode* pNode = CWorld::GetSector(i, j)->m_lists[ENTITYLIST_BUILDINGS].first; pNode; pNode = pNode->next) {
+				CEntity* pEntity = (CEntity*)pNode->item;
+				if (MODELID_CRANE_1 == pEntity->GetModelIndex() ||
+					MODELID_CRANE_2 == pEntity->GetModelIndex() ||
+					MODELID_CRANE_3 == pEntity->GetModelIndex())
+					AddThisOneCrane(pEntity);
+			}
+		}
+	}
+	for (CPtrNode* pNode = CWorld::GetBigBuildingList(LEVEL_INDUSTRIAL).first; pNode; pNode = pNode->next) {
+		CEntity* pEntity = (CEntity*)pNode->item;
+		if (MODELID_CRANE_1 == pEntity->GetModelIndex() ||
+			MODELID_CRANE_2 == pEntity->GetModelIndex() ||
+			MODELID_CRANE_3 == pEntity->GetModelIndex())
+			AddThisOneCrane(pEntity);
+	}
+}
+
+void CCranes::AddThisOneCrane(CEntity* pEntity)
+{
+	pEntity->GetMatrix().ResetOrientation();
+	if (NumCranes >= NUM_CRANES)
+		return;
+	CCrane* pCrane = &aCranes[NumCranes];
+	pCrane->Init();
+	pCrane->m_pCraneEntity = (CBuilding*)pEntity;
+	pCrane->m_nCraneStatus = CCrane::NONE;
+	pCrane->m_fHookAngle = NumCranes; // lol wtf
+	while (pCrane->m_fHookAngle > TWOPI)
+		pCrane->m_fHookAngle -= TWOPI;
+	pCrane->m_fHookOffset = DEFAULT_OFFSET;
+	pCrane->m_fHookHeight = DEFAULT_OFFSET;
+	pCrane->m_nTimeForNextCheck = 0;
+	pCrane->m_nCraneState = CCrane::IDLE;
+	pCrane->m_bWasMilitaryCrane = false;
+	pCrane->m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &aCranes[NumCranes]);
+	if (pCrane->m_nAudioEntity >= 0)
+		DMAudio.SetEntityStatus(pCrane->m_nAudioEntity, 1);
+	pCrane->m_bIsTop = (MODELID_CRANE_1 != pEntity->GetModelIndex());
+	// Is this used to avoid military crane?
+	if (pCrane->m_bIsTop || pEntity->GetPosition().y > 0.0f) {
+		CObject* pHook = new CObject(MI_MAGNET, false);
+		pHook->ObjectCreatedBy = MISSION_OBJECT;
+		pHook->bUsesCollision = false;
+		pHook->bExplosionProof = true;
+		pHook->bAffectedByGravity = false;
+		pCrane->m_pHook = pHook;
+		pCrane->CalcHookCoordinates(&pCrane->m_vecHookCurPos.x, &pCrane->m_vecHookCurPos.y, &pCrane->m_vecHookCurPos.z);
+		pCrane->SetHookMatrix();
+	}
+	else
+		pCrane->m_pHook = nil;
+	NumCranes++;
+}
+
+void CCranes::ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY, float fDropOffX, float fDropOffY, float fDropOffZ, float fHeading, bool bIsCrusher, bool bIsMilitary, float fPosX, float fPosY)
+{
+	float fMinDistance = MAX_DISTANCE;
+	float X = fPosX, Y = fPosY;
+	if (X <= MIN_VALID_POSITION || Y <= MIN_VALID_POSITION) {
+		X = fDropOffX;
+		Y = fDropOffY;
+	}
+	int index = 0;
+	for (int i = 0; i < NumCranes; i++) {
+		float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
+		if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
+			fMinDistance = distance;
+			index = i;
+		}
+	}
+#ifdef FIX_BUGS // classic
+	if (fMinDistance == MAX_DISTANCE)
+		return;
+#endif
+	CCrane* pCrane = &aCranes[index];
+	pCrane->m_fPickupX1 = fInfX;
+	pCrane->m_fPickupX2 = fSupX;
+	pCrane->m_fPickupY1 = fInfY;
+	pCrane->m_fPickupY2 = fSupY;
+	pCrane->m_vecDropoffTarget.x = fDropOffX;
+	pCrane->m_vecDropoffTarget.y = fDropOffY;
+	pCrane->m_vecDropoffTarget.z = fDropOffZ;
+	pCrane->m_nCraneStatus = CCrane::ACTIVATED;
+	pCrane->m_pVehiclePickedUp = nil;
+	pCrane->m_nVehiclesCollected = 0;
+	pCrane->m_fDropoffHeading = fHeading;
+	pCrane->m_bIsCrusher = bIsCrusher;
+	pCrane->m_bIsMilitaryCrane = bIsMilitary;
+	bool military = true;
+	if (!bIsMilitary && !pCrane->m_bWasMilitaryCrane)
+		military = false;
+	pCrane->m_bWasMilitaryCrane = military;
+	pCrane->m_nTimeForNextCheck = 0;
+	pCrane->m_nCraneState = CCrane::IDLE;
+	float Z;
+	if (bIsCrusher)
+		Z = CRUSHER_Z;
+	else if (bIsMilitary)
+		Z = MILITARY_Z;
+	else
+		Z = CWorld::FindGroundZForCoord((fInfX + fSupX) / 2, (fInfY + fSupY) / 2);
+	pCrane->FindParametersForTarget((fInfX + fSupX) / 2, (fInfY + fSupY) / 2, Z, &pCrane->m_fPickupAngle, &pCrane->m_fPickupDistance, &pCrane->m_fPickupHeight);
+	pCrane->FindParametersForTarget(fDropOffX, fDropOffY, fDropOffZ, &pCrane->m_fDropoffAngle, &pCrane->m_fDropoffDistance, &pCrane->m_fDropoffHeight);
+}
+
+void CCranes::DeActivateCrane(float X, float Y)
+{
+	float fMinDistance = MAX_DISTANCE;
+	int index = 0;
+	for (int i = 0; i < NumCranes; i++) {
+		float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
+		if (distance < fMinDistance && distance < MAX_DISTANCE_TO_FIND_CRANE) {
+			fMinDistance = distance;
+			index = i;
+		}
+	}
+#ifdef FIX_BUGS // classic
+	if (fMinDistance == MAX_DISTANCE)
+		return;
+#endif
+	aCranes[index].m_nCraneStatus = CCrane::DEACTIVATED;
+	aCranes[index].m_nCraneState = CCrane::IDLE;
+}
+
+bool CCranes::IsThisCarPickedUp(float X, float Y, CVehicle* pVehicle)
+{
+	int index = 0;
+	bool result = false;
+	for (int i = 0; i < NumCranes; i++) {
+		float distance = (CVector2D(X, Y) - aCranes[i].m_pCraneEntity->GetPosition()).Magnitude();
+		if (distance < MAX_DISTANCE_TO_FIND_CRANE && aCranes[i].m_pVehiclePickedUp == pVehicle) {
+			if (aCranes[i].m_nCraneStatus == CCrane::LIFTING_TARGET || aCranes[i].m_nCraneStatus == CCrane::ROTATING_TARGET)
+				result = true;
+		}
+	}
+	return true;
+}
+
+void CCranes::UpdateCranes(void)
+{
+	for (int i = 0; i < NumCranes; i++) {
+		if (aCranes[i].m_bIsTop || aCranes[i].m_bIsCrusher ||
+			(TheCamera.GetPosition().x + CRANE_UPDATE_RADIUS > aCranes[i].m_pCraneEntity->GetPosition().x &&
+				TheCamera.GetPosition().x - CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().x &&
+				TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS > aCranes[i].m_pCraneEntity->GetPosition().y &&
+				TheCamera.GetPosition().y + CRANE_UPDATE_RADIUS < aCranes[i].m_pCraneEntity->GetPosition().y))
+			aCranes[i].Update();
+	}
+}
+
+void CCrane::Update(void)
+{
+	if (CReplay::IsPlayingBack())
+		return;
+	if (((m_nCraneStatus == ACTIVATED || m_nCraneStatus == DEACTIVATED) &&
+		Abs(TheCamera.GetGameCamPosition().x - m_pCraneEntity->GetPosition().x) < CRANE_MOVEMENT_PROCESSING_RADIUS &&
+		Abs(TheCamera.GetGameCamPosition().y - m_pCraneEntity->GetPosition().y) < CRANE_MOVEMENT_PROCESSING_RADIUS) ||
+		m_nCraneState != IDLE) {
+		switch (m_nCraneState) {
+		case IDLE:
+			if (GoTowardsTarget(m_fPickupAngle, m_fPickupDistance, GetHeightToPickup()) &&
+				CTimer::GetTimeInMilliseconds() > m_nTimeForNextCheck) {
+				CWorld::AdvanceCurrentScanCode();
+#ifdef FIX_BUGS
+				int xstart = max(0, CWorld::GetSectorIndexX(m_fPickupX1));
+				int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(m_fPickupX2));
+				int ystart = max(0, CWorld::GetSectorIndexY(m_fPickupY1));
+				int yend = min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(m_fPickupY2));
+#else
+				int xstart = CWorld::GetSectorIndexX(m_fPickupX1);
+				int xend = CWorld::GetSectorIndexX(m_fPickupX2);
+				int ystart = CWorld::GetSectorIndexY(m_fPickupY1);
+				int yend = CWorld::GetSectorIndexY(m_fPickupY1);
+#endif
+				assert(xstart <= xend);
+				assert(ystart <= yend);
+				for (int i = xstart; i <= xend; i++) {
+					for (int j = ystart; j <= yend; j++) {
+						FindCarInSectorList(&CWorld::GetSector(i, j)->m_lists[ENTITYLIST_VEHICLES]);
+						FindCarInSectorList(&CWorld::GetSector(i, j)->m_lists[ENTITYLIST_VEHICLES_OVERLAP]);
+					}
+				}
+			}
+			break;
+		case GOING_TOWARDS_TARGET:
+			if (m_pVehiclePickedUp){
+				if (m_pVehiclePickedUp->GetPosition().x < m_fPickupX1 ||
+					m_pVehiclePickedUp->GetPosition().x > m_fPickupX2 ||
+					m_pVehiclePickedUp->GetPosition().y < m_fPickupY1 ||
+					m_pVehiclePickedUp->GetPosition().y > m_fPickupY2 ||
+					m_pVehiclePickedUp->pDriver ||
+					Abs(m_pVehiclePickedUp->GetMoveSpeed().x) > CAR_MOVING_SPEED_THRESHOLD ||
+					Abs(m_pVehiclePickedUp->GetMoveSpeed().y) > CAR_MOVING_SPEED_THRESHOLD ||
+					Abs(m_pVehiclePickedUp->GetMoveSpeed().z) > CAR_MOVING_SPEED_THRESHOLD ||
+					FindPlayerPed()->GetPedState() == PED_ENTER_CAR && // TODO: fix carjack bug
+					FindPlayerPed()->m_pSeekTarget == m_pVehiclePickedUp) {
+					m_pVehiclePickedUp = nil;
+					m_nCraneState = IDLE;
+				}
+				else {
+					float fAngle, fOffset, fHeight;
+					FindParametersForTarget(
+						m_pVehiclePickedUp->GetPosition().x,
+						m_pVehiclePickedUp->GetPosition().y,
+						m_pVehiclePickedUp->GetPosition().z + m_pVehiclePickedUp->GetColModel()->boundingBox.max.z,
+						&fAngle, &fOffset, &fHeight);
+					if (GoTowardsTarget(fAngle, fOffset, fHeight)) {
+						CVector distance = m_pVehiclePickedUp->GetPosition() - m_vecHookCurPos;
+						distance.z += m_pVehiclePickedUp->GetColModel()->boundingBox.max.z;
+						if (distance.MagnitudeSqr() < SQR(DISTANCE_FROM_HOOK_TO_VEHICLE_TO_COLLECT)) {
+							m_nCraneState = GOING_TOWARDS_TARGET_ONLY_HEIGHT;
+							m_vecHookVelocity *= 0.4f;
+							m_pVehiclePickedUp->bLightsOn = false;
+							m_pVehiclePickedUp->bUsesCollision = false;
+							if (m_bIsCrusher)
+								m_pVehiclePickedUp->bCollisionProof = true;
+							DMAudio.PlayOneShot(m_nAudioEntity, SOUND_CRANE_PICKUP, 0.0f);
+						}
+					}
+				}
+			}
+			else
+				m_nCraneState = IDLE;
+			break;
+		case LIFTING_TARGET:
+			RotateCarriedCarProperly();
+			if (GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, GetHeightToDropoff(), CRANE_SLOWDOWN_MULTIPLIER))
+				m_nCraneState = ROTATING_TARGET;
+			if (!m_pVehiclePickedUp || m_pVehiclePickedUp->pDriver) {
+				m_pVehiclePickedUp = nil;
+				m_nCraneState = IDLE;
+			}
+			break;
+		case GOING_TOWARDS_TARGET_ONLY_HEIGHT:
+			RotateCarriedCarProperly();
+			if (GoTowardsHeightTarget(GetHeightToPickupHeight(), CRANE_SLOWDOWN_MULTIPLIER))
+				m_nCraneState = LIFTING_TARGET;
+			TimerForCamInterpolation = CTimer::GetTimeInMilliseconds();
+			if (!m_pVehiclePickedUp || m_pVehiclePickedUp->pDriver) {
+				m_pVehiclePickedUp = nil;
+				m_nCraneState = IDLE;
+			}
+			break;
+		case ROTATING_TARGET:
+		{
+			bool bRotateFinished = RotateCarriedCarProperly();
+			bool bMovementFinished = GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, m_fDropoffHeight, 0.3f);
+			if (bMovementFinished && bRotateFinished) {
+				float fDistanceFromPlayer = m_pVehiclePickedUp ? ((CVector2D)FindPlayerCoors() - (CVector2D)m_pVehiclePickedUp->GetPosition()).Magnitude() : 0.0f;
+				if (fDistanceFromPlayer > DISTANCE_FROM_PLAYER_TO_REMOVE_VEHICLE || !m_bWasMilitaryCrane) {
+					m_nCraneState = DROPPING_TARGET;
+					if (m_pVehiclePickedUp) {
+						m_pVehiclePickedUp->bUsesCollision = true;
+						m_pVehiclePickedUp->m_nStaticFrames = 0;
+						++m_nVehiclesCollected;
+						if (m_bIsMilitaryCrane) {
+							CCranes::RegisterCarForMilitaryCrane(m_pVehiclePickedUp->GetModelIndex());
+							if (!CCranes::HaveAllCarsBeenCollectedByMilitaryCrane()) {
+								CWorld::Players[CWorld::PlayerInFocus].m_nMoney += CAR_REWARD_MILITARY_CRANE;
+								CGarages::TriggerMessage("GA_10", CAR_REWARD_MILITARY_CRANE, MESSAGE_SHOW_DURATION, -1);
+							}
+							CWorld::Remove(m_pVehiclePickedUp);
+							delete m_pVehiclePickedUp;
+						}
+					}
+					m_pVehiclePickedUp = nil;
+				}
+			}
+			break;
+		}
+		case DROPPING_TARGET:
+			if (GoTowardsTarget(m_fDropoffAngle, m_fDropoffDistance, GetHeightToDropoffHeight(), CRANE_SLOWDOWN_MULTIPLIER)) {
+				m_nCraneState = IDLE;
+				m_nTimeForNextCheck = CTimer::GetTimeInMilliseconds() + 10000;
+			}
+			break;
+		default:
+			break;
+		}
+		CVector vecHook;
+		CalcHookCoordinates(&vecHook.x, &vecHook.y, &vecHook.z);
+		m_vecHookVelocity += ((CVector2D)vecHook - (CVector2D)m_vecHookCurPos) * CTimer::GetTimeStep() * CRANE_MOVEMENT_SPEED;
+		m_vecHookVelocity *= Pow(0.98f, CTimer::GetTimeStep());
+		m_vecHookCurPos.x += m_vecHookVelocity.x * CTimer::GetTimeStep();
+		m_vecHookCurPos.y += m_vecHookVelocity.y * CTimer::GetTimeStep();
+		m_vecHookCurPos.z = vecHook.z;
+		switch (m_nCraneState) {
+		case LIFTING_TARGET:
+		case GOING_TOWARDS_TARGET_ONLY_HEIGHT:
+		case ROTATING_TARGET:
+			if (m_pVehiclePickedUp) {
+				m_pVehiclePickedUp->GetPosition() = CVector(m_vecHookCurPos.x, m_vecHookCurPos.y, m_vecHookCurPos.z - m_pVehiclePickedUp->GetColModel()->boundingBox.max.z);
+				m_pVehiclePickedUp->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+				CVector up(vecHook.x - m_vecHookCurPos.x, vecHook.y - m_vecHookCurPos.y, 20.0f);
+				up.Normalise();
+				m_pVehiclePickedUp->GetRight() = CrossProduct(m_pVehiclePickedUp->GetForward(), up);
+				m_pVehiclePickedUp->GetForward() = CrossProduct(up, m_pVehiclePickedUp->GetRight());
+				m_pVehiclePickedUp->GetUp() = up;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	else {
+		int16 rnd = (m_pCraneEntity->m_randomSeed + (CTimer::GetTimeInMilliseconds() >> 11)) & 0xF;
+		// 16 options, lasting 2048 ms each
+		// a bit awkward: why there are 4 periods for -= and 6 for +=? is it a bug?
+		if (rnd < 4) {
+			m_fHookAngle -= OSCILLATION_SPEED * CTimer::GetTimeStep();
+			if (m_fHookAngle < 0.0f)
+				m_fHookAngle += TWOPI;
+		}
+		else if (rnd > 5 && rnd < 12) {
+			m_fHookAngle += OSCILLATION_SPEED * CTimer::GetTimeStep();
+			if (m_fHookAngle > TWOPI)
+				m_fHookAngle -= TWOPI;
+		}
+		CalcHookCoordinates(&m_vecHookCurPos.x, &m_vecHookCurPos.y, &m_vecHookCurPos.z);
+		m_vecHookVelocity.x = m_vecHookVelocity.y = 0.0f;
+	}
+	float fCos = Cos(m_fHookAngle);
+	float fSin = Sin(m_fHookAngle);
+	m_pCraneEntity->GetRight().x = fCos;
+	m_pCraneEntity->GetForward().y = fCos;
+	m_pCraneEntity->GetRight().y = fSin;
+	m_pCraneEntity->GetForward().x = -fSin;
+	m_pCraneEntity->GetMatrix().UpdateRW();
+	m_pCraneEntity->UpdateRwFrame();
+	SetHookMatrix();
+}
+
+bool CCrane::RotateCarriedCarProperly()
+{
+	if (m_fDropoffHeading <= 0.0f)
+		return true;
+	if (!m_pVehiclePickedUp)
+		return true;
+	float fAngleDelta = m_fDropoffHeading - CGeneral::GetATanOfXY(m_pVehiclePickedUp->GetForward().x, m_pVehiclePickedUp->GetForward().y);
+	while (fAngleDelta < -HALFPI)
+		fAngleDelta += PI;
+	while (fAngleDelta > HALFPI)
+		fAngleDelta -= PI;
+	float fDeltaThisFrame = CAR_ROTATION_SPEED * CTimer::GetTimeStep();
+	if (Abs(fAngleDelta) <= fDeltaThisFrame) // no rotation is actually applied?
+		return true;
+	m_pVehiclePickedUp->GetMatrix().RotateZ(Abs(fDeltaThisFrame));
+	return false;
+}
+
+void CCrane::FindCarInSectorList(CPtrList* pList)
+{
+	CPtrNode* node;
+	for (node = pList->first; node; node = node->next) {
+		CVehicle* pVehicle = (CVehicle*)node->item;
+		if (pVehicle->m_scanCode == CWorld::GetCurrentScanCode())
+			continue;
+		pVehicle->m_scanCode = CWorld::GetCurrentScanCode();
+		if (pVehicle->GetPosition().x < m_fPickupX1 || pVehicle->GetPosition().x > m_fPickupX2 ||
+			pVehicle->GetPosition().y < m_fPickupY1 || pVehicle->GetPosition().y > m_fPickupY2)
+			continue;
+		if (pVehicle->pDriver)
+			continue;
+		if (Abs(pVehicle->GetMoveSpeed().x) >= CAR_MOVING_SPEED_THRESHOLD ||
+			Abs(pVehicle->GetMoveSpeed().y) >= CAR_MOVING_SPEED_THRESHOLD ||
+			Abs(pVehicle->GetMoveSpeed().z) >= CAR_MOVING_SPEED_THRESHOLD)
+			continue;
+		if (!pVehicle->IsCar() || pVehicle->m_status == STATUS_WRECKED || pVehicle->m_fHealth < 250.0f)
+			continue;
+		if (!DoesCranePickUpThisCarType(pVehicle->GetModelIndex()) ||
+			m_bIsMilitaryCrane && CCranes::DoesMilitaryCraneHaveThisOneAlready(pVehicle->GetModelIndex())) {
+			if (!pVehicle->bCraneMessageDone) {
+				pVehicle->bCraneMessageDone = true;
+				if (!m_bIsMilitaryCrane)
+					CGarages::TriggerMessage("CR_1", -1, MESSAGE_SHOW_DURATION, -1); // Crane cannot lift this vehicle.
+				else if (DoesCranePickUpThisCarType(pVehicle->GetModelIndex()))
+					CGarages::TriggerMessage("GA_20", -1, MESSAGE_SHOW_DURATION, -1); // We got more of these than we can shift. Sorry man, no deal.
+				else
+					CGarages::TriggerMessage("GA_19", -1, MESSAGE_SHOW_DURATION, -1); // We're not interested in that model.
+			}
+		}
+		else {
+			m_pVehiclePickedUp = pVehicle;
+			pVehicle->RegisterReference((CEntity**)&m_pVehiclePickedUp);
+			m_nCraneState = GOING_TOWARDS_TARGET;
+		}
+	}
+}
+
+bool CCrane::DoesCranePickUpThisCarType(uint32 mi)
+{
+	if (m_bIsCrusher) {
+		return mi != MI_FIRETRUCK &&
+			mi != MI_TRASH &&
+#ifndef FIX_BUGS // why
+			mi != MI_BLISTA &&
+#endif
+			mi != MI_SECURICA &&
+			mi != MI_BUS &&
+			mi != MI_DODO &&
+			mi != MI_RHINO;
+	}
+	if (m_bIsMilitaryCrane) {
+		return mi == MI_FIRETRUCK ||
+			mi == MI_AMBULAN ||
+			mi == MI_ENFORCER ||
+			mi == MI_FBICAR ||
+			mi == MI_RHINO ||
+			mi == MI_BARRACKS ||
+			mi == MI_POLICE;
+	}
+	return true;
+}
+
+bool CCranes::DoesMilitaryCraneHaveThisOneAlready(uint32 mi)
+{
+	switch (mi) {
+	case MI_FIRETRUCK: return (CarsCollectedMilitaryCrane & 1);
+	case MI_AMBULAN: return (CarsCollectedMilitaryCrane & 2);
+	case MI_ENFORCER: return (CarsCollectedMilitaryCrane & 4);
+	case MI_FBICAR: return (CarsCollectedMilitaryCrane & 8);
+	case MI_RHINO: return (CarsCollectedMilitaryCrane & 0x10);
+	case MI_BARRACKS: return (CarsCollectedMilitaryCrane & 0x20);
+	case MI_POLICE: return (CarsCollectedMilitaryCrane & 0x40);
+	default: break;
+	}
+	return false;
+}
+
+void CCranes::RegisterCarForMilitaryCrane(uint32 mi)
+{
+	switch (mi) {
+	case MI_FIRETRUCK: CarsCollectedMilitaryCrane |= 1; break;
+	case MI_AMBULAN: CarsCollectedMilitaryCrane |= 2; break;
+	case MI_ENFORCER: CarsCollectedMilitaryCrane |= 4; break;
+	case MI_FBICAR: CarsCollectedMilitaryCrane |= 8; break;
+	case MI_RHINO: CarsCollectedMilitaryCrane |= 0x10; break;
+	case MI_BARRACKS: CarsCollectedMilitaryCrane |= 0x20; break;
+	case MI_POLICE: CarsCollectedMilitaryCrane |= 0x40; break;
+	default: break;
+	}
+}
+
+bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane()
+{
+	return (CarsCollectedMilitaryCrane & 0x7F) == 0x7F;
+}
+
+bool CCrane::GoTowardsTarget(float fAngleToTarget, float fDistanceToTarget, float fTargetHeight, float fSpeedMultiplier)
+{
+	bool bAngleMovementFinished, bOffsetMovementFinished, bHeightMovementFinished;
+	float fHookAngleDelta = fAngleToTarget - m_fHookAngle;
+	while (fHookAngleDelta > PI)
+		fHookAngleDelta -= TWOPI;
+	while (fHookAngleDelta < -PI)
+		fHookAngleDelta += TWOPI;
+	float fHookAngleChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_ANGLE_MOVEMENT_SPEED;
+	if (Abs(fHookAngleDelta) < fHookAngleChangeThisFrame) {
+		m_fHookAngle = fAngleToTarget;
+		bAngleMovementFinished = true;
+	} else {
+		if (fHookAngleDelta < 0.0f) {
+			m_fHookAngle -= fHookAngleChangeThisFrame;
+			if (m_fHookAngle < 0.0f)
+				m_fHookAngle += TWOPI;
+		}
+		else {
+			m_fHookAngle += fHookAngleChangeThisFrame;
+			if (m_fHookAngle > TWOPI)
+				m_fHookAngle -= TWOPI;
+		}
+		bAngleMovementFinished = false;
+	}
+	float fHookOffsetDelta = fDistanceToTarget - m_fHookOffset;
+	float fHookOffsetChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_OFFSET_MOVEMENT_SPEED;
+	if (Abs(fHookOffsetDelta) < fHookOffsetChangeThisFrame) {
+		m_fHookOffset = fDistanceToTarget;
+		bOffsetMovementFinished = true;
+	} else {
+		if (fHookOffsetDelta < 0.0f)
+			m_fHookOffset -= fHookOffsetChangeThisFrame;
+		else
+			m_fHookOffset += fHookOffsetChangeThisFrame;
+		bOffsetMovementFinished = false;
+	}
+	float fHookHeightDelta = fTargetHeight - m_fHookHeight;
+	float fHookHeightChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_HEIGHT_MOVEMENT_SPEED;
+	if (Abs(fHookHeightDelta) < fHookHeightChangeThisFrame) {
+		m_fHookHeight = fTargetHeight;
+		bHeightMovementFinished = true;
+	} else {
+		if (fHookHeightDelta < 0.0f)
+			m_fHookHeight -= fHookHeightChangeThisFrame;
+		else
+			m_fHookHeight += fHookHeightChangeThisFrame;
+		bHeightMovementFinished = false;
+	}
+	return bAngleMovementFinished && bOffsetMovementFinished && bHeightMovementFinished;
+}
+
+bool CCrane::GoTowardsHeightTarget(float fTargetHeight, float fSpeedMultiplier)
+{
+	bool bHeightMovementFinished;
+	float fHookHeightDelta = fTargetHeight - m_fHookHeight;
+	float fHookHeightChangeThisFrame = fSpeedMultiplier * CTimer::GetTimeStep() * HOOK_HEIGHT_MOVEMENT_SPEED;
+	if (Abs(fHookHeightDelta) < fHookHeightChangeThisFrame) {
+		m_fHookHeight = fTargetHeight;
+		bHeightMovementFinished = true;
+	} else {
+		if (fHookHeightDelta < 0.0f)
+			m_fHookHeight -= fHookHeightChangeThisFrame;
+		else
+			m_fHookHeight += fHookHeightChangeThisFrame;
+		bHeightMovementFinished = false;
+	}
+	return bHeightMovementFinished;
+}
+
+void CCrane::FindParametersForTarget(float X, float Y, float Z, float* pAngle, float* pDistance, float* pHeight)
+{
+	*pAngle = CGeneral::GetATanOfXY(X - m_pCraneEntity->GetPosition().x, Y - m_pCraneEntity->GetPosition().y);
+	*pDistance = ((CVector2D(X, Y) - (CVector2D)m_pCraneEntity->GetPosition())).Magnitude();
+	*pHeight = Z;
+}
+
+void CCrane::CalcHookCoordinates(float* pX, float* pY, float* pZ)
+{
+	*pX = Cos(m_fHookAngle) * m_fHookOffset + m_pCraneEntity->GetPosition().x;
+	*pY = Sin(m_fHookAngle) * m_fHookOffset + m_pCraneEntity->GetPosition().y;
+	*pZ = m_fHookHeight;
+}
+
+void CCrane::SetHookMatrix()
+{
+	if (m_pHook == nil)
+		return;
+	m_pHook->GetPosition() = m_vecHookCurPos;
+	CVector up(m_vecHookInitPos.x - m_vecHookCurPos.x, m_vecHookInitPos.y - m_vecHookCurPos.y, 20.0f);
+	up.Normalise();
+	m_pHook->GetRight() = CrossProduct(CVector(0.0f, 1.0f, 0.0f), up);
+	m_pHook->GetForward() = CrossProduct(up, m_pHook->GetRight());
+	m_pHook->GetUp() = up;
+	m_pHook->SetOrientation(0.0f, 0.0f, -HALFPI);
+	m_pHook->GetMatrix().UpdateRW();
+	m_pHook->UpdateRwFrame();
+	CWorld::Remove(m_pHook);
+	CWorld::Add(m_pHook);
+}
+
+bool CCranes::IsThisCarBeingCarriedByAnyCrane(CVehicle* pVehicle)
+{
+	for (int i = 0; i < NumCranes; i++) {
+		if (pVehicle == aCranes[i].m_pVehiclePickedUp) {
+			switch (aCranes[i].m_nCraneState) {
+			case CCrane::GOING_TOWARDS_TARGET_ONLY_HEIGHT:
+			case CCrane::LIFTING_TARGET:
+			case CCrane::ROTATING_TARGET:
+				return true;
+			default:
+				break;
+			}
+		}
+	}
+	return false;
+}
+
+bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle* pVehicle)
+{
+	for (int i = 0; i < NumCranes; i++) {
+		if (pVehicle == aCranes[i].m_pVehiclePickedUp)
+			return true;
+	}
+	return false;
+}
+
+void CCranes::Save(uint8* buf, uint32* size)
+{
+	INITSAVEBUF
+
+	*size = 2 * sizeof(uint32) + sizeof(aCranes);
+	WriteSaveBuf(buf, NumCranes);
+	WriteSaveBuf(buf, CarsCollectedMilitaryCrane);
+	for (int i = 0; i < NUM_CRANES; i++) {
+		CCrane *pCrane = WriteSaveBuf(buf, aCranes[i]);
+		if (pCrane->m_pCraneEntity != nil)
+			pCrane->m_pCraneEntity = (CBuilding*)(CPools::GetBuildingPool()->GetJustIndex(pCrane->m_pCraneEntity) + 1);
+		if (pCrane->m_pHook != nil)
+			pCrane->m_pHook = (CObject*)(CPools::GetObjectPool()->GetJustIndex(pCrane->m_pHook) + 1);
+		if (pCrane->m_pVehiclePickedUp != nil)
+			pCrane->m_pVehiclePickedUp = (CVehicle*)(CPools::GetVehiclePool()->GetJustIndex(pCrane->m_pVehiclePickedUp) + 1);
+	}
+
+	VALIDATESAVEBUF(*size);
+}
+
+void CCranes::Load(uint8* buf, uint32 size)
+{
+	INITSAVEBUF
+
+	NumCranes = ReadSaveBuf<int32>(buf);
+	CarsCollectedMilitaryCrane = ReadSaveBuf<uint32>(buf);
+	for (int i = 0; i < NUM_CRANES; i++)
+		aCranes[i] = ReadSaveBuf<CCrane>(buf);
+	for (int i = 0; i < NUM_CRANES; i++) {
+		CCrane *pCrane = &aCranes[i];
+		if (pCrane->m_pCraneEntity != nil)
+			pCrane->m_pCraneEntity = CPools::GetBuildingPool()->GetSlot((uint32)pCrane->m_pCraneEntity - 1);
+		if (pCrane->m_pHook != nil)
+			pCrane->m_pHook = CPools::GetObjectPool()->GetSlot((uint32)pCrane->m_pHook - 1);
+		if (pCrane->m_pVehiclePickedUp != nil)
+			pCrane->m_pVehiclePickedUp = CPools::GetVehiclePool()->GetSlot((uint32)pCrane->m_pVehiclePickedUp - 1);
+	}
+	for (int i = 0; i < NUM_CRANES; i++) {
+		aCranes[i].m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &aCranes[i]);
+		if (aCranes[i].m_nAudioEntity != 0)
+			DMAudio.SetEntityStatus(aCranes[i].m_nAudioEntity, 1);
+	}
+
+	VALIDATESAVEBUF(size);
+}
diff --git a/src/vehicles/Cranes.h b/src/vehicles/Cranes.h
new file mode 100644
index 00000000..c0502638
--- /dev/null
+++ b/src/vehicles/Cranes.h
@@ -0,0 +1,97 @@
+#pragma once
+#include "common.h"
+
+#include "World.h"
+
+class CVehicle;
+class CEntity;
+class CObject;
+class CBuilding;
+
+class CCrane
+{
+public:
+	enum CraneState : uint8 {
+		IDLE = 0,
+		GOING_TOWARDS_TARGET = 1,
+		LIFTING_TARGET = 2,
+		GOING_TOWARDS_TARGET_ONLY_HEIGHT = 3,
+		ROTATING_TARGET = 4,
+		DROPPING_TARGET = 5
+	};
+	enum CraneStatus : uint8 {
+		NONE = 0,
+		ACTIVATED = 1,
+		DEACTIVATED = 2
+	};
+	CBuilding *m_pCraneEntity;
+	CObject *m_pHook;
+	int32 m_nAudioEntity;
+	float m_fPickupX1;
+	float m_fPickupX2;
+	float m_fPickupY1;
+	float m_fPickupY2;
+	CVector m_vecDropoffTarget;
+	float m_fDropoffHeading;
+	float m_fPickupAngle;
+	float m_fDropoffAngle;
+	float m_fPickupDistance;
+	float m_fDropoffDistance;
+	float m_fPickupHeight;
+	float m_fDropoffHeight;
+	float m_fHookAngle;
+	float m_fHookOffset;
+	float m_fHookHeight;
+	CVector m_vecHookInitPos;
+	CVector m_vecHookCurPos;
+	CVector2D m_vecHookVelocity;
+	CVehicle *m_pVehiclePickedUp;
+	uint32 m_nTimeForNextCheck;
+	CraneStatus m_nCraneStatus;
+	CraneState m_nCraneState;
+	uint8 m_nVehiclesCollected;
+	bool m_bIsCrusher;
+	bool m_bIsMilitaryCrane;
+	bool m_bWasMilitaryCrane;
+	bool m_bIsTop;
+
+	void Init(void) { memset(this, 0, sizeof(*this)); }
+	void Update(void);
+	bool RotateCarriedCarProperly(void);
+	void FindCarInSectorList(CPtrList* pList);
+	bool DoesCranePickUpThisCarType(uint32 mi);
+	bool GoTowardsTarget(float fAngleToTarget, float fDistanceToTarget, float fTargetHeight, float fSpeedMultiplier = 1.0f);
+	bool GoTowardsHeightTarget(float fTargetHeight, float fSpeedMultiplier = 1.0f);
+	void FindParametersForTarget(float X, float Y, float Z, float* pAngle, float* pDistance, float* pHeight);
+	void CalcHookCoordinates(float* pX, float* pY, float* pZ);
+	void SetHookMatrix(void);
+
+	float GetHeightToPickup() { return 4.0f + m_fPickupHeight + (m_bIsCrusher ? 4.5f : 0.0f); };
+	float GetHeightToDropoff() { return m_bIsCrusher ? (2.0f + m_fDropoffHeight + 3.0f) : (2.0f + m_fDropoffHeight); }
+	float GetHeightToPickupHeight() { return m_fPickupHeight + (m_bIsCrusher ? 7.0f : 4.0f); }
+	float GetHeightToDropoffHeight() { return m_fDropoffHeight + (m_bIsCrusher ? 7.0f : 2.0f); }
+};
+
+static_assert(sizeof(CCrane) == 128, "CCrane: error");
+
+class CCranes
+{
+public:
+	static void InitCranes(void);
+	static void AddThisOneCrane(CEntity* pCraneEntity);
+	static void ActivateCrane(float fInfX, float fSupX, float fInfY, float fSupY, float fDropOffX, float fDropOffY, float fDropOffZ, float fHeading, bool bIsCrusher, bool bIsMilitary, float fPosX, float fPosY);
+	static void DeActivateCrane(float fX, float fY);
+	static bool IsThisCarPickedUp(float fX, float fY, CVehicle* pVehicle);
+	static void UpdateCranes(void);
+	static bool DoesMilitaryCraneHaveThisOneAlready(uint32 mi);
+	static void RegisterCarForMilitaryCrane(uint32 mi);
+	static bool HaveAllCarsBeenCollectedByMilitaryCrane(void);
+	static bool IsThisCarBeingCarriedByAnyCrane(CVehicle* pVehicle);
+	static bool IsThisCarBeingTargettedByAnyCrane(CVehicle* pVehicle);
+	static void Save(uint8* buf, uint32* size);
+	static void Load(uint8* buf, uint32 size); // on mobile it's CranesLoad outside of the class
+
+	static uint32 CarsCollectedMilitaryCrane;
+	static int32 NumCranes;
+	static CCrane aCranes[NUM_CRANES];
+};
diff --git a/src/vehicles/Floater.cpp b/src/vehicles/Floater.cpp
index 6b8bf755..62d55925 100644
--- a/src/vehicles/Floater.cpp
+++ b/src/vehicles/Floater.cpp
@@ -26,7 +26,7 @@ cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVec
 {
 	m_numSteps = 2.0f;
 
-	if(!CWaterLevel::GetWaterLevel(phys->GetPosition(), &m_waterlevel, phys->m_flagD8))
+	if(!CWaterLevel::GetWaterLevel(phys->GetPosition(), &m_waterlevel, phys->bTouchingWater))
 		return false;
 	m_matrix = phys->GetMatrix();
 
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index adeba19e..f47fd131 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -481,6 +481,55 @@ CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage
 		FindPlayerPed()->SetWantedLevelNoDrop(1);
 }
 
+void
+CVehicle::DoFixedMachineGuns(void)
+{
+	if(CPad::GetPad(0)->GetCarGunFired() && !bGunSwitchedOff){
+		if(CTimer::GetTimeInMilliseconds() > m_nGunFiringTime + 150){
+			CVector source, target;
+			float dx, dy, len;
+
+			dx = GetForward().x;
+			dy = GetForward().y;
+			len = Sqrt(SQR(dx) + SQR(dy));
+			if(len < 0.1f) len = 0.1f;
+			dx /= len;
+			dy /= len;
+
+			m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
+
+			source = GetMatrix() * CVector(2.0f, 2.5f, 1.0f);
+			target = source + CVector(dx, dy, 0.0f)*60.0f;
+			target += CVector(
+				((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
+				((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
+				((CGeneral::GetRandomNumber()&0xFF)-128) * 0.02f);
+			CWeapon::DoTankDoomAiming(this, pDriver, &source, &target);
+			FireOneInstantHitRound(&source, &target, 15);
+
+			source = GetMatrix() * CVector(-2.0f, 2.5f, 1.0f);
+			target = source + CVector(dx, dy, 0.0f)*60.0f;
+			target += CVector(
+				((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
+				((CGeneral::GetRandomNumber()&0xFF)-128) * 0.015f,
+				((CGeneral::GetRandomNumber()&0xFF)-128) * 0.02f);
+			CWeapon::DoTankDoomAiming(this, pDriver, &source, &target);
+			FireOneInstantHitRound(&source, &target, 15);
+
+			DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+
+			m_nAmmoInClip--;
+			if(m_nAmmoInClip == 0){
+				m_nAmmoInClip = 20;
+				m_nGunFiringTime = CTimer::GetTimeInMilliseconds() + 1400;
+			}
+		}
+	}else{
+		if(CTimer::GetTimeInMilliseconds() > m_nGunFiringTime + 1400)
+			m_nAmmoInClip = 20;
+	}
+}
+
 void
 CVehicle::ExtinguishCarFire(void)
 {
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 4639f3e1..f9becda0 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -130,7 +130,8 @@ public:
 	int8 m_nGettingInFlags;
 	int8 m_nGettingOutFlags;
 	uint8 m_nNumMaxPassengers;
-	char field_1CD[19];
+	char field_1CD[3];
+	float field_1D0[4];
 	CEntity *m_pCurGroundEntity;
 	CFire *m_pCarFire;
 	float m_fSteerAngle;
@@ -238,6 +239,7 @@ public:
 	bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; }
 	bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; }
 	bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; }
+	bool IsBike(void) { return m_vehType == VEHICLE_TYPE_BIKE; }
 
 	void FlyingControl(eFlightModel flightModel);
 	void ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
@@ -268,6 +270,7 @@ public:
 	bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
 	bool ShufflePassengersToMakeSpace(void);
 	void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage);
+	void DoFixedMachineGuns(void);
 
 	bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
 	CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
diff --git a/src/weapons/Explosion.cpp b/src/weapons/Explosion.cpp
index e99dc918..3d00052a 100644
--- a/src/weapons/Explosion.cpp
+++ b/src/weapons/Explosion.cpp
@@ -1,11 +1,29 @@
 #include "common.h"
 #include "patcher.h"
+#include "Automobile.h"
+#include "Bike.h"
+#include "Camera.h"
+#include "Coronas.h"
 #include "DMAudio.h"
+#include "Entity.h"
+#include "EventList.h"
 #include "Explosion.h"
+#include "General.h"
+#include "Fire.h"
+#include "Pad.h"
+#include "Particle.h"
+#include "PointLights.h"
+#include "Shadows.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "WaterLevel.h"
+#include "World.h"
 
-CExplosion(&gaExplosion)[48] = *(CExplosion(*)[48])*(uintptr*)0x64E208;
+CExplosion(&gaExplosion)[NUM_EXPLOSIONS] = *(CExplosion(*)[NUM_EXPLOSIONS])*(uintptr*)0x64E208;
 
-WRAPPER void CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32) { EAXJMP(0x5591C0); }
+// these two were not initialised in original code, I'm really not sure what were they meant to be
+RwRGBA colMedExpl = { 0, 0, 0, 0 };
+RwRGBA colUpdate = { 0, 0, 0, 0 };
 
 int AudioHandle = AEHANDLE_NONE;
 
@@ -15,26 +33,25 @@ CExplosion::Initialise()
 	debug("Initialising CExplosion...\n");
 	for (int i = 0; i < ARRAY_SIZE(gaExplosion); i++) {
 		gaExplosion[i].m_ExplosionType = EXPLOSION_GRENADE;
-		gaExplosion[i].m_vecPosition.x = 0.0f;
-		gaExplosion[i].m_vecPosition.y = 0.0f;
-		gaExplosion[i].m_vecPosition.z = 0.0f;
+		gaExplosion[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f);
 		gaExplosion[i].m_fRadius = 1.0f;
 		gaExplosion[i].m_fPropagationRate = 0.0f;
-		gaExplosion[i].field_38 = 0;
+		gaExplosion[i].m_fZshift = 0.0f;
 		gaExplosion[i].m_pCreatorEntity = nil;
 		gaExplosion[i].m_pVictimEntity = nil;
 		gaExplosion[i].m_fStopTime = 0.0f;
-		gaExplosion[i].m_bActive = false;
-		gaExplosion[i].m_nStartTime = 0;
-		gaExplosion[i].field_34 = 0;
+		gaExplosion[i].m_nIteration = 0;
+		gaExplosion[i].m_fStartTime = 0.0f;
+		gaExplosion[i].m_bIsBoat = false;
 	}
 	AudioHandle = DMAudio.CreateEntity(AUDIOTYPE_EXPLOSION, (void*)1);
 	if (AudioHandle >= 0)
-		DMAudio.SetEntityStatus(AudioHandle, 1);
+		DMAudio.SetEntityStatus(AudioHandle, true);
 	debug("CExplosion ready\n");
 }
 
-void CExplosion::Shutdown()
+void
+CExplosion::Shutdown()
 {
 	debug("Shutting down CExplosion...\n");
 	if (AudioHandle >= 0) {
@@ -44,27 +61,16 @@ void CExplosion::Shutdown()
 	debug("CExplosion shut down\n");
 }
 
-void
-CExplosion::RemoveAllExplosionsInArea(CVector pos, float radius)
-{
-	for (int i = 0; i < ARRAY_SIZE(gaExplosion); i++) {
-		if (gaExplosion[i].m_bActive) {
-			if ((pos - gaExplosion[i].m_vecPosition).MagnitudeSqr() < SQR(radius))
-				gaExplosion[i].m_bActive = false;
-		}
-	}
-}
-
 int8
 CExplosion::GetExplosionActiveCounter(uint8 id)
 {
-	return gaExplosion[id].m_bActiveCounter;
+	return gaExplosion[id].m_nActiveCounter;
 }
 
-CVector *
-CExplosion::GetExplosionPosition(uint8 id)
+void
+CExplosion::ResetExplosionActiveCounter(uint8 id)
 {
-	return &gaExplosion[id].m_vecPosition;
+	gaExplosion[id].m_nActiveCounter = 0;
 }
 
 uint8
@@ -73,18 +79,363 @@ CExplosion::GetExplosionType(uint8 id)
 	return gaExplosion[id].m_ExplosionType;
 }
 
-void
-CExplosion::ResetExplosionActiveCounter(uint8 id)
+CVector *
+CExplosion::GetExplosionPosition(uint8 id)
 {
-	gaExplosion[id].m_bActiveCounter = 0;
+	return &gaExplosion[id].m_vecPosition;
 }
 
 bool
-CExplosion::TestForExplosionInArea(eExplosionType a1, float x1, float x2, float y1, float y2, float z1, float z2)
+CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime)
+{
+	CVector pPosn;
+	CVector posGround;
+
+	RwRGBA colorMedium = colMedExpl;
+	bool bDontExplode = false;
+	const RwRGBA color = { 160, 160, 160, 255 };
+	pPosn = pos;
+	pPosn.z += 5.0f;
+#ifdef FIX_BUGS
+	CShadows::AddPermanentShadow(SHADOWTEX_CAR, gpShadowHeliTex, &pPosn, 8.0f, 0.0f, 0.0f, -8.0f, 200, 0, 0, 0, 10.0f, 30000, 1.0f);
+#else
+	// last two arguments are swapped resulting in no shadow
+	CShadows::AddPermanentShadow(SHADOWTEX_CAR, gpShadowHeliTex, &pPosn, 8.0f, 0.0f, 0.0f, -8.0f, 200, 0, 0, 0, 10.0f, 1, 30000.0f);
+#endif
+
+	int n = 0;
+	while (gaExplosion[n].m_nIteration != 0 && n < ARRAY_SIZE(gaExplosion))
+		n++;
+	if (n == ARRAY_SIZE(gaExplosion))
+		return false;
+
+	CExplosion &explosion = gaExplosion[n];
+	explosion.m_ExplosionType = type;
+	explosion.m_vecPosition = pos;
+	explosion.m_fRadius = 1.0f;
+	explosion.m_fZshift = 0.0f;
+	explosion.m_pCreatorEntity = culprit;
+	if (culprit != nil)
+		culprit->RegisterReference(&explosion.m_pCreatorEntity);
+	explosion.m_pVictimEntity = explodingEntity;
+	if (explodingEntity != nil)
+		explodingEntity->RegisterReference(&explosion.m_pVictimEntity);
+	explosion.m_nIteration = 1;
+	explosion.m_nActiveCounter = 1;
+	explosion.m_bIsBoat = false;
+	explosion.m_nParticlesExpireTime = lifetime != 0 ? CTimer::GetTimeInMilliseconds() + lifetime : 0;
+	switch (type)
+	{
+	case EXPLOSION_GRENADE:
+		explosion.m_fRadius = 9.0f;
+		explosion.m_fPower = 300.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750;
+		explosion.m_fPropagationRate = 0.5f;
+		posGround = pos;
+		posGround.z = CWorld::FindGroundZFor3DCoord(posGround.x, posGround.y, posGround.z + 3.0f, nil);
+		CEventList::RegisterEvent(EVENT_EXPLOSION, posGround, 250);
+		if (Distance(explosion.m_vecPosition, TheCamera.GetPosition()) < 40.0f)
+			CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, explosion.m_vecPosition, CVector(0.0f, 0.0f, 0.0f), nil, 5.5f, color);
+		break;
+	case EXPLOSION_MOLOTOV:
+	{
+		explosion.m_fRadius = 6.0f;
+		explosion.m_fPower = 0.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 3000;
+		explosion.m_fPropagationRate = 0.5f;
+		posGround = pos;
+		bool found;
+		posGround.z = CWorld::FindGroundZFor3DCoord(posGround.x, posGround.y, posGround.z + 3.0f, &found);
+		if (found) {
+			float waterLevel;
+			if (CWaterLevel::GetWaterLevelNoWaves(posGround.x, posGround.y, posGround.z, &waterLevel)
+				&& posGround.z < waterLevel
+				&& waterLevel - 6.0f < posGround.z) // some subway/tunnels check?
+				bDontExplode = true;
+			else
+				gFireManager.StartFire(posGround, 1.8f, false);
+		}
+		else
+			bDontExplode = true;
+		break;
+	}
+	case EXPLOSION_ROCKET:
+		explosion.m_fRadius = 10.0f;
+		explosion.m_fPower = 300.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750;
+		explosion.m_fPropagationRate = 0.5f;
+		CEventList::RegisterEvent(EVENT_EXPLOSION, pos, 250);
+		if (Distance(explosion.m_vecPosition, TheCamera.GetPosition()) < 40.0f)
+			CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, explosion.m_vecPosition, CVector(0.0f, 0.0f, 0.0f), nil, 5.5f, color);
+		break;
+	case EXPLOSION_CAR:
+	case EXPLOSION_CAR_QUICK:
+		explosion.m_fRadius = 9.0f;
+		explosion.m_fPower = 300.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 4250;
+		explosion.m_fPropagationRate = 0.5f;
+		explosion.m_fStartTime = CTimer::GetTimeInMilliseconds();
+		if (explosion.m_pVictimEntity != nil) {
+			if (explosion.m_pVictimEntity->IsVehicle() && ((CVehicle*)explosion.m_pVictimEntity)->IsBoat())
+				explosion.m_bIsBoat = true;
+			CEventList::RegisterEvent(EVENT_EXPLOSION, EVENT_ENTITY_VEHICLE, explosion.m_pVictimEntity, nil, 1000);
+		} else 
+			CEventList::RegisterEvent(EVENT_EXPLOSION, pos, 1000);
+
+		if (explosion.m_pVictimEntity != nil && !explosion.m_bIsBoat) {
+			int rn = (CGeneral::GetRandomNumber() & 1) + 2;
+			for (int i = 0; i < rn; i++) {
+				CParticle::AddParticle(PARTICLE_EXPLOSION_MEDIUM, explosion.m_pVictimEntity->GetPosition(), CVector(0.0f, 0.0f, 0.0f), nil, 3.5f, colMedExpl);
+				CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, explosion.m_pVictimEntity->GetPosition(), CVector(0.0f, 0.0f, 0.0f), nil, 5.5f, color);
+			}
+			CVehicle *veh = (CVehicle*)explosion.m_pVictimEntity;
+			int32 component = CAR_WING_LR;
+
+			// miami leftover
+			if (veh->IsBike())
+				component = BIKE_FORKS_REAR;
+
+			if (veh->IsComponentPresent(component)) {
+				CVector componentPos;
+				veh->GetComponentWorldPosition(component, componentPos);
+				rn = (CGeneral::GetRandomNumber() & 1) + 1;
+				for (int i = 0; i < rn; i++)
+					CParticle::AddJetExplosion(componentPos, 1.4f, 0.0f);
+			}
+		}
+		break;
+	case EXPLOSION_HELI:
+		explosion.m_fRadius = 6.0f;
+		explosion.m_fPower = 300.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750;
+		explosion.m_fPropagationRate = 0.5f;
+		explosion.m_fStartTime = CTimer::GetTimeInMilliseconds();
+		for (int i = 0; i < 10; i++) {
+			CVector randpos;
+			uint8 x, y, z;
+
+			x = CGeneral::GetRandomNumber();
+			y = CGeneral::GetRandomNumber();
+			z = CGeneral::GetRandomNumber();
+			randpos = pos + CVector(x - 128, y - 128, z - 128) / 20.0f;
+
+			CParticle::AddParticle(PARTICLE_EXPLOSION_MFAST, randpos, CVector(0.0f, 0.0f, 0.0f), nil, 2.5f, color);
+
+			x = CGeneral::GetRandomNumber();
+			y = CGeneral::GetRandomNumber();
+			z = CGeneral::GetRandomNumber();
+			randpos = pos + CVector(x - 128, y - 128, z - 128) / 20.0f;
+
+			CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, randpos, CVector(0.0f, 0.0f, 0.0f), nil, 5.0f, color);
+
+			x = CGeneral::GetRandomNumber();
+			y = CGeneral::GetRandomNumber();
+			z = CGeneral::GetRandomNumber();
+			randpos = pos + CVector(x - 128, y - 128, z - 128) / 20.0f;
+
+			CParticle::AddJetExplosion(randpos, 1.4f, 3.0f);
+		}
+		CEventList::RegisterEvent(EVENT_EXPLOSION, pos, 1000);
+		break;
+	case EXPLOSION_MINE:
+		explosion.m_fRadius = 10.0f;
+		explosion.m_fPower = 150.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750;
+		explosion.m_fPropagationRate = 0.5f;
+		posGround = pos;
+		//posGround.z = 
+			CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z + 4.0f, nil); // BUG? result is unused
+		CEventList::RegisterEvent(EVENT_EXPLOSION, posGround, 250);
+		break;
+	case EXPLOSION_BARREL:
+		explosion.m_fRadius = 7.0f;
+		explosion.m_fPower = 150.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750;
+		explosion.m_fPropagationRate = 0.5f;
+		for (int i = 0; i < 6; i++) {
+			CVector randpos;
+			uint8 x, y, z;
+
+			x = CGeneral::GetRandomNumber();
+			y = CGeneral::GetRandomNumber();
+			z = CGeneral::GetRandomNumber();
+			randpos = CVector(x - 128, y - 128, z - 128);
+
+			randpos.x /= 50.0f;
+			randpos.y /= 50.0f;
+			randpos.z /= 25.0f;
+			randpos += pos;
+			CParticle::AddParticle(PARTICLE_EXPLOSION_MEDIUM, randpos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, colorMedium);
+		}
+		posGround = pos;
+		//posGround.z = 
+			CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z + 4.0f, nil); // BUG? result is unused
+		CEventList::RegisterEvent(EVENT_EXPLOSION, posGround, 250);
+		break;
+	case EXPLOSION_TANK_GRENADE:
+		explosion.m_fRadius = 10.0f;
+		explosion.m_fPower = 150.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750;
+		explosion.m_fPropagationRate = 0.5f;
+		posGround = pos;
+		//posGround.z = 
+			CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z + 4.0f, nil); // BUG? result is unused
+		CEventList::RegisterEvent(EVENT_EXPLOSION, posGround, 250);
+		break;
+	case EXPLOSION_HELI_BOMB:
+		explosion.m_fRadius = 8.0f;
+		explosion.m_fPower = 50.0f;
+		explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750;
+		explosion.m_fPropagationRate = 0.5f;
+		posGround = pos;
+		//posGround.z = 
+			CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z + 4.0f, nil); // BUG? result is unused
+		CEventList::RegisterEvent(EVENT_EXPLOSION, posGround, 250);
+		break;
+	}
+	if (bDontExplode) {
+		explosion.m_nIteration = 0;
+		return false;
+	}
+
+	if (explosion.m_fPower != 0.0f && explosion.m_nParticlesExpireTime == 0)
+		CWorld::TriggerExplosion(pos, explosion.m_fRadius, explosion.m_fPower, culprit, (type == EXPLOSION_ROCKET || type == EXPLOSION_CAR_QUICK || type == EXPLOSION_MINE || type == EXPLOSION_BARREL || type == EXPLOSION_TANK_GRENADE || type == EXPLOSION_HELI_BOMB));
+
+	TheCamera.CamShake(0.6f, pos.x, pos.y, pos.z);
+	CPad::GetPad(0)->StartShake_Distance(300, 128, pos.x, pos.y, pos.z);
+	return true;
+}
+
+void
+CExplosion::Update()
+{
+	RwRGBA color = colUpdate;
+	for (int i = 0; i < ARRAY_SIZE(gaExplosion); i++) {
+		CExplosion &explosion = gaExplosion[i];
+		if (explosion.m_nIteration == 0) continue;
+
+		if (explosion.m_nParticlesExpireTime != 0) {
+			if (CTimer::GetTimeInMilliseconds() > explosion.m_nParticlesExpireTime) {
+				explosion.m_nParticlesExpireTime = 0;
+				if (explosion.m_fPower != 0.0f)
+					CWorld::TriggerExplosion(explosion.m_vecPosition, explosion.m_fRadius, explosion.m_fPower, explosion.m_pCreatorEntity, (explosion.m_ExplosionType == EXPLOSION_ROCKET || explosion.m_ExplosionType == EXPLOSION_CAR_QUICK || explosion.m_ExplosionType == EXPLOSION_MINE || explosion.m_ExplosionType == EXPLOSION_BARREL || explosion.m_ExplosionType == EXPLOSION_TANK_GRENADE || explosion.m_ExplosionType == EXPLOSION_HELI_BOMB));
+			}
+		} else {
+			explosion.m_fRadius += explosion.m_fPropagationRate * CTimer::GetTimeStep();
+			int32 someTime = explosion.m_fStopTime - CTimer::GetTimeInMilliseconds();
+			switch (explosion.m_ExplosionType)
+			{
+			case EXPLOSION_GRENADE:
+			case EXPLOSION_ROCKET:
+			case EXPLOSION_HELI:
+			case EXPLOSION_MINE:
+			case EXPLOSION_BARREL:
+				if (CTimer::GetFrameCounter() & 1) {
+					CPointLights::AddLight(CPointLights::LIGHT_POINT, explosion.m_vecPosition, CVector(0.0f, 0.0f, 0.0f), 20.0f, 1.0f, 1.0f, 0.5f, CPointLights::FOG_NONE, true);
+					CCoronas::RegisterCorona((uintptr)&explosion, 255, 255, 200, 255, explosion.m_vecPosition, 8.0f, 120.0f, gpCoronaTexture[0], CCoronas::TYPE_NORMAL, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+				} else
+					CCoronas::RegisterCorona((uintptr)&explosion, 128, 128, 100, 255, explosion.m_vecPosition, 8.0f, 120.0f, gpCoronaTexture[0], CCoronas::TYPE_NORMAL, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+				CCoronas::RegisterCorona((uintptr)&explosion + 1, 30, 30, 25, 255, explosion.m_vecPosition, explosion.m_fRadius, 120.0f, gpCoronaTexture[7], CCoronas::TYPE_STAR, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+				break;
+			case EXPLOSION_MOLOTOV:
+				CWorld::SetPedsOnFire(explosion.m_vecPosition.x, explosion.m_vecPosition.y, explosion.m_vecPosition.z, 6.0f, explosion.m_pCreatorEntity);
+				CWorld::SetCarsOnFire(explosion.m_vecPosition.x, explosion.m_vecPosition.y, explosion.m_vecPosition.z, 6.0f, explosion.m_pCreatorEntity);
+				if (explosion.m_nIteration < 10) {
+					if (explosion.m_nIteration == 1) {
+						CVector point1 = explosion.m_vecPosition;
+						point1.z += 5.0f;
+						CColPoint colPoint;
+						CEntity *pEntity;
+						CWorld::ProcessVerticalLine(point1, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil);
+						explosion.m_fZshift = colPoint.point.z;
+					}
+					float ff = ((float)explosion.m_nIteration * 0.55f);
+					for (int i = 0; i < 5 * ff; i++) {
+						float angle = CGeneral::GetRandomNumber() / 256.0f * 6.28f;
+
+						CVector pos = explosion.m_vecPosition;
+						pos.x += ff * Sin(angle);
+						pos.y += ff * Cos(angle);
+						pos.z += 5.0f; // what is the point of this?
+
+						pos.z = explosion.m_fZshift + 0.5f;
+						CParticle::AddParticle(PARTICLE_EXPLOSION_MEDIUM, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, CGeneral::GetRandomNumberInRange(-3.0f, 3.0f), CGeneral::GetRandomNumberInRange(-180.0f, 180.0f));
+					}
+				}
+				break;
+			case EXPLOSION_CAR:
+			case EXPLOSION_CAR_QUICK:
+				if (someTime >= 3500) {
+					if (explosion.m_pVictimEntity != nil && !explosion.m_bIsBoat) {
+						if ((CGeneral::GetRandomNumber() & 0xF) == 0) {
+							CVehicle *veh = (CVehicle*)explosion.m_pVictimEntity;
+							uint8 component = CAR_WING_LR;
+
+							// miami leftover
+							if (veh->IsBike())
+								component = BIKE_FORKS_REAR;
+
+							if (veh->IsComponentPresent(component)) {
+								CVector componentPos;
+								veh->GetComponentWorldPosition(component, componentPos);
+								CParticle::AddJetExplosion(componentPos, 1.5f, 0.0f);
+							}
+						}
+						if (CTimer::GetTimeInMilliseconds() > explosion.m_fStartTime) {
+							explosion.m_fStartTime = CTimer::GetTimeInMilliseconds() + 125 + (CGeneral::GetRandomNumber() & 0x7F);
+							CVector pos = explosion.m_pVictimEntity->GetPosition();
+							for (int i = 0; i < (CGeneral::GetRandomNumber() & 1) + 1; i++) {
+								CParticle::AddParticle(PARTICLE_EXPLOSION_MEDIUM, pos, CVector(0.0f, 0.0f, 0.0f), nil, 3.5f, color);
+								CParticle::AddParticle(PARTICLE_EXPLOSION_LARGE, pos, CVector(0.0f, 0.0f, 0.0f), nil, 5.5f, color);
+							}
+						}
+					}
+					if (CTimer::GetFrameCounter() & 1) {
+						CPointLights::AddLight(CPointLights::LIGHT_POINT, explosion.m_vecPosition, CVector(0.0f, 0.0f, 0.0f), 15.0f, 1.0f, 0.0f, 0.0f, CPointLights::FOG_NONE, true);
+						CCoronas::RegisterCorona((uintptr)&explosion, 200, 100, 0, 255, explosion.m_vecPosition, 6.0f, 80.0f, gpCoronaTexture[0], CCoronas::TYPE_NORMAL, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+					} else
+						CCoronas::RegisterCorona((uintptr)&explosion, 128, 0, 0, 255, explosion.m_vecPosition, 8.0f, 80.0f, gpCoronaTexture[0], CCoronas::TYPE_NORMAL, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+
+					CCoronas::RegisterCorona((uintptr)&explosion + 1, 30, 15, 0, 255, explosion.m_vecPosition, explosion.m_fRadius, 80.0f, gpCoronaTexture[7], CCoronas::TYPE_STAR, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+				} else if (explosion.m_nIteration & 1) {
+					if (explosion.m_pVictimEntity != nil)
+						CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, explosion.m_pVictimEntity->GetPosition(), CVector(0.0f, 0.0f, 0.0f), nil, CGeneral::GetRandomNumberInRange(0.5f, 0.8f), color);
+					CVector pos = explosion.m_vecPosition;
+					pos.z += 1.0f;
+					CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, pos, CVector(0.0f, 0.0f, 0.11f), nil, CGeneral::GetRandomNumberInRange(0.5f, 2.0f), color);
+				}
+				break;
+			case EXPLOSION_TANK_GRENADE:
+			case EXPLOSION_HELI_BOMB:
+				if (explosion.m_nIteration < 5) {
+					float ff = ((float)explosion.m_nIteration * 0.65f);
+					for (int i = 0; i < 10 * ff; i++) {
+						uint8 x = CGeneral::GetRandomNumber(), y = CGeneral::GetRandomNumber(), z = CGeneral::GetRandomNumber();
+						CVector pos(x - 128, y - 128, (z % 128) + 1);
+
+						pos.Normalise();
+						pos *= ff / 5.0f;
+						pos += explosion.m_vecPosition;
+						pos.z += 0.5f;
+						CParticle::AddParticle(PARTICLE_EXPLOSION_LARGE, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, CGeneral::GetRandomNumberInRange(-3.0f, 3.0f), CGeneral::GetRandomNumberInRange(-180.0f, 180.0f));
+					}
+				}
+				break;
+			}
+			if (someTime > 0)
+				explosion.m_nIteration++;
+			else
+				explosion.m_nIteration = 0;
+		}
+	}
+}
+
+bool
+CExplosion::TestForExplosionInArea(eExplosionType type, float x1, float x2, float y1, float y2, float z1, float z2)
 {
 	for (int i = 0; i < ARRAY_SIZE(gaExplosion); i++) {
-		if (gaExplosion[i].m_bActive) {
-			if (a1 == gaExplosion[i].m_ExplosionType) {
+		if (gaExplosion[i].m_nIteration != 0) {
+			if (type == gaExplosion[i].m_ExplosionType) {
 				if (gaExplosion[i].m_vecPosition.x >= x1 && gaExplosion[i].m_vecPosition.x <= x2) {
 					if (gaExplosion[i].m_vecPosition.y >= y1 && gaExplosion[i].m_vecPosition.y <= y2) {
 						if (gaExplosion[i].m_vecPosition.z >= z1 && gaExplosion[i].m_vecPosition.z <= z2)
@@ -97,13 +448,26 @@ CExplosion::TestForExplosionInArea(eExplosionType a1, float x1, float x2, float
 	return false;
 }
 
+void
+CExplosion::RemoveAllExplosionsInArea(CVector pos, float radius)
+{
+	for (int i = 0; i < ARRAY_SIZE(gaExplosion); i++) {
+		if (gaExplosion[i].m_nIteration != 0) {
+			if ((pos - gaExplosion[i].m_vecPosition).MagnitudeSqr() < SQR(radius))
+				gaExplosion[i].m_nIteration = 0;
+		}
+	}
+}
+
 STARTPATCHES
 	InjectHook(0x559030, &CExplosion::Initialise, PATCH_JUMP);
 	InjectHook(0x559100, &CExplosion::Shutdown, PATCH_JUMP);
-	InjectHook(0x55AD40, &CExplosion::RemoveAllExplosionsInArea, PATCH_JUMP);
 	InjectHook(0x559140, &CExplosion::GetExplosionActiveCounter, PATCH_JUMP);
-	InjectHook(0x5591A0, &CExplosion::GetExplosionPosition, PATCH_JUMP);
-	InjectHook(0x559180, &CExplosion::GetExplosionType, PATCH_JUMP);
 	InjectHook(0x559160, &CExplosion::ResetExplosionActiveCounter, PATCH_JUMP);
+	InjectHook(0x559180, &CExplosion::GetExplosionType, PATCH_JUMP);
+	InjectHook(0x5591A0, &CExplosion::GetExplosionPosition, PATCH_JUMP);
+	InjectHook(0x5591C0, &CExplosion::AddExplosion, PATCH_JUMP);
+	InjectHook(0x55A0C0, &CExplosion::Update, PATCH_JUMP);
 	InjectHook(0x55AC80, &CExplosion::TestForExplosionInArea, PATCH_JUMP);
+	InjectHook(0x55AD40, &CExplosion::RemoveAllExplosionsInArea, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/weapons/Explosion.h b/src/weapons/Explosion.h
index e6ef9496..45e2d5bb 100644
--- a/src/weapons/Explosion.h
+++ b/src/weapons/Explosion.h
@@ -26,25 +26,24 @@ class CExplosion
 	CEntity *m_pCreatorEntity;
 	CEntity *m_pVictimEntity;
 	float m_fStopTime;
-	bool m_bActive;
-	int8 m_bActiveCounter;
-	int32 m_nStartTime;
+	uint8 m_nIteration;
+	uint8 m_nActiveCounter;
+	float m_fStartTime;
 	uint32 m_nParticlesExpireTime;
 	float m_fPower;
-	int32 field_34;
-	int32 field_38;
+	bool m_bIsBoat;
+	float m_fZshift;
 public:
 	static void Initialise();
 	static void Shutdown();
-	static void AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type,
-	                         const CVector &pos, uint32);
-
 	static int8 GetExplosionActiveCounter(uint8 id);
-	static CVector *GetExplosionPosition(uint8 id);
-	static uint8 GetExplosionType(uint8 id);
 	static void ResetExplosionActiveCounter(uint8 id);
-	static void RemoveAllExplosionsInArea(CVector, float);
-	static bool TestForExplosionInArea(eExplosionType, float, float, float, float, float, float);
+	static uint8 GetExplosionType(uint8 id);
+	static CVector *GetExplosionPosition(uint8 id);
+	static bool AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime);
+	static void Update();
+	static bool TestForExplosionInArea(eExplosionType type, float x1, float x2, float y1, float y2, float z1, float z2);
+	static void RemoveAllExplosionsInArea(CVector pos, float radius);
 };
 
-extern CExplosion (&gaExplosion)[48];
\ No newline at end of file
+extern CExplosion (&gaExplosion)[NUM_EXPLOSIONS];
\ No newline at end of file
diff --git a/src/weapons/ProjectileInfo.h b/src/weapons/ProjectileInfo.h
index dafb48db..a4ea369a 100644
--- a/src/weapons/ProjectileInfo.h
+++ b/src/weapons/ProjectileInfo.h
@@ -1,32 +1,32 @@
-#pragma once
-
-class CEntity;
-class CObject;
-class CProjectile;
-enum eWeaponType;
-
-class CProjectileInfo
-{
-public:
-	eWeaponType m_eWeaponType;
-	CEntity* m_pSource;
-	uint32 m_nExplosionTime;
-	bool m_bInUse;
-	CVector m_vecPos;
-
-public:
-	static CProjectileInfo* GetProjectileInfo(int32 id);
-	static CProjectile* (&ms_apProjectile)[NUM_PROJECTILES];
-
-	static void Initialise();
-	static void Shutdown();
-	static bool AddProjectile(CEntity *ped, eWeaponType weapon, CVector pos, float speed);
-	static void RemoveProjectile(CProjectileInfo *info, CProjectile *projectile);
-	static void RemoveNotAdd(CEntity *entity, eWeaponType weaponType, CVector pos);
-	static bool RemoveIfThisIsAProjectile(CObject *pObject);
-	static void RemoveAllProjectiles();
-	static void Update();
-	static bool IsProjectileInRange(float x1, float x2, float y1, float y2, float z1, float z2, bool remove);
-};
-
+#pragma once
+
+class CEntity;
+class CObject;
+class CProjectile;
+enum eWeaponType;
+
+class CProjectileInfo
+{
+public:
+	eWeaponType m_eWeaponType;
+	CEntity* m_pSource;
+	uint32 m_nExplosionTime;
+	bool m_bInUse;
+	CVector m_vecPos;
+
+public:
+	static CProjectileInfo* GetProjectileInfo(int32 id);
+	static CProjectile* (&ms_apProjectile)[NUM_PROJECTILES];
+
+	static void Initialise();
+	static void Shutdown();
+	static bool AddProjectile(CEntity *ped, eWeaponType weapon, CVector pos, float speed);
+	static void RemoveProjectile(CProjectileInfo *info, CProjectile *projectile);
+	static void RemoveNotAdd(CEntity *entity, eWeaponType weaponType, CVector pos);
+	static bool RemoveIfThisIsAProjectile(CObject *pObject);
+	static void RemoveAllProjectiles();
+	static void Update();
+	static bool IsProjectileInRange(float x1, float x2, float y1, float y2, float z1, float z2, bool remove);
+};
+
 extern CProjectileInfo (&gaProjectileInfo)[NUM_PROJECTILES];
\ No newline at end of file