diff --git a/README.md b/README.md
index 6e8f717c..3c394e62 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,6 @@ CBoat
 CBrightLights
 CBulletInfo
 CBulletTraces
-CCam
 CCamera
 CCopPed
 CCrane
diff --git a/rwsdk/include/d3d8/rwplcore.h b/rwsdk/include/d3d8/rwplcore.h
index 152261cc..b0ff7dfa 100644
--- a/rwsdk/include/d3d8/rwplcore.h
+++ b/rwsdk/include/d3d8/rwplcore.h
@@ -3906,8 +3906,8 @@ MACRO_STOP
 #pragma warning( disable : 344 )
 #endif /* (defined(__ICL)) */
 
-
-#include <windows.h>
+//nobody needed that - AAP
+//#include <windows.h>
 
 #if (defined(RWDEBUG))
 #if (defined(RWMEMDEBUG) && !defined(_CRTDBG_MAP_ALLOC))
diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp
index ec42191b..246322ba 100644
--- a/src/animation/AnimBlendAssociation.cpp
+++ b/src/animation/AnimBlendAssociation.cpp
@@ -203,6 +203,15 @@ CAnimBlendAssociation::UpdateBlend(float timeDelta)
 	return true;
 }
 
+#include <new>
+
+class CAnimBlendAssociation_ : public CAnimBlendAssociation
+{
+public:
+	CAnimBlendAssociation *ctor1(void) { return ::new (this) CAnimBlendAssociation(); }
+	CAnimBlendAssociation *ctor2(CAnimBlendAssociation &other) { return ::new (this) CAnimBlendAssociation(other); }
+	void dtor(void) { this->CAnimBlendAssociation::~CAnimBlendAssociation(); }
+};
 
 STARTPATCHES
 	InjectHook(0x4016A0, &CAnimBlendAssociation::AllocateAnimBlendNodeArray, PATCH_JUMP);
@@ -219,7 +228,7 @@ STARTPATCHES
 	InjectHook(0x4031F0, &CAnimBlendAssociation::UpdateTime, PATCH_JUMP);
 	InjectHook(0x4032B0, &CAnimBlendAssociation::UpdateBlend, PATCH_JUMP);
 
-	InjectHook(0x401460, &CAnimBlendAssociation::ctor1, PATCH_JUMP);
-	InjectHook(0x4014C0, &CAnimBlendAssociation::ctor2, PATCH_JUMP);
-	InjectHook(0x401520, &CAnimBlendAssociation::dtor, PATCH_JUMP);
+	InjectHook(0x401460, &CAnimBlendAssociation_::ctor1, PATCH_JUMP);
+	InjectHook(0x4014C0, &CAnimBlendAssociation_::ctor2, PATCH_JUMP);
+	InjectHook(0x401520, &CAnimBlendAssociation_::dtor, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h
index aec28f56..d35db1db 100644
--- a/src/animation/AnimBlendAssociation.h
+++ b/src/animation/AnimBlendAssociation.h
@@ -85,9 +85,5 @@ public:
 	static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) {
 		return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link));
 	}
-
-	CAnimBlendAssociation *ctor1(void) { return ::new (this) CAnimBlendAssociation(); }
-	CAnimBlendAssociation *ctor2(CAnimBlendAssociation &other) { return ::new (this) CAnimBlendAssociation(other); }
-	void dtor(void) { this->CAnimBlendAssociation::~CAnimBlendAssociation(); }
 };
 static_assert(sizeof(CAnimBlendAssociation) == 0x40, "CAnimBlendAssociation: error");
diff --git a/src/animation/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp
index 06625eb5..cc4281d6 100644
--- a/src/animation/AnimBlendClumpData.cpp
+++ b/src/animation/AnimBlendClumpData.cpp
@@ -36,9 +36,19 @@ CAnimBlendClumpData::ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *
 		cb(&frames[i], arg);
 }
 
+#include <new>
+
+class CAnimBlendClumpData_ : public CAnimBlendClumpData
+{
+public:
+	CAnimBlendClumpData *ctor(void) { return ::new (this) CAnimBlendClumpData(); }
+	void dtor(void) { this->CAnimBlendClumpData::~CAnimBlendClumpData(); }
+};
+
+
 STARTPATCHES
-	InjectHook(0x401880, &CAnimBlendClumpData::ctor, PATCH_JUMP);
-	InjectHook(0x4018B0, &CAnimBlendClumpData::dtor, PATCH_JUMP);
+	InjectHook(0x401880, &CAnimBlendClumpData_::ctor, PATCH_JUMP);
+	InjectHook(0x4018B0, &CAnimBlendClumpData_::dtor, PATCH_JUMP);
 	InjectHook(0x4018F0, &CAnimBlendClumpData::SetNumberOfFrames, PATCH_JUMP);
 	InjectHook(0x401930, &CAnimBlendClumpData::ForAllFrames, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/animation/AnimBlendClumpData.h b/src/animation/AnimBlendClumpData.h
index df2fbc56..1c8c391d 100644
--- a/src/animation/AnimBlendClumpData.h
+++ b/src/animation/AnimBlendClumpData.h
@@ -49,9 +49,5 @@ public:
 	void SetNumberOfBones(int n) { SetNumberOfFrames(n); }
 #endif
 	void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg);
-
-
-	CAnimBlendClumpData *ctor(void) { return ::new (this) CAnimBlendClumpData(); }
-	void dtor(void) { this->CAnimBlendClumpData::~CAnimBlendClumpData(); }
 };
 static_assert(sizeof(CAnimBlendClumpData) == 0x14, "CAnimBlendClumpData: error");
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index daa27e57..608a209a 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -11,19 +11,10 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754;
 
 WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); }
 
-enum
-{
-	NodeTypeExtern = 1,
-	NodeTypeIntern = 2,
-
-	ObjectFlag1 = 1,
-	ObjectEastWest = 2,
-
-	MAX_DIST = INT16_MAX-1
-};
+#define MAX_DIST INT16_MAX-1
 
 // object flags:
-//	1
+//	1	UseInRoadBlock
 //	2	east/west road(?)
 
 CPathInfoForObject *&InfoForTileCars = *(CPathInfoForObject**)0x8F1A8C;
@@ -218,14 +209,14 @@ CPathFind::PreparePathData(void)
 			if(numIntern == 1 && numExtern == 2){
 				if(numLanes < 4){
 					if((i & 7) == 4){		// WHAT?
-						m_objectFlags[i] |= ObjectFlag1;
+						m_objectFlags[i] |= UseInRoadBlock;
 						if(maxX > maxY)
 							m_objectFlags[i] |= ObjectEastWest;
 						else
 							m_objectFlags[i] &= ~ObjectEastWest;
 					}
 				}else{
-					m_objectFlags[i] |= ObjectFlag1;
+					m_objectFlags[i] |= UseInRoadBlock;
 					if(maxX > maxY)
 						m_objectFlags[i] |= ObjectEastWest;
 					else
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index d42b8bb3..c51cb7c7 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -9,6 +9,15 @@ public:
 	static bool CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16);
 };
 
+enum
+{
+	NodeTypeExtern = 1,
+	NodeTypeIntern = 2,
+
+	UseInRoadBlock = 1,
+	ObjectEastWest = 2,
+};
+
 enum
 {
 	PATH_CAR = 0,
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
index ed092391..e39fe481 100644
--- a/src/control/RoadBlocks.cpp
+++ b/src/control/RoadBlocks.cpp
@@ -1,7 +1,37 @@
 #include "common.h"
 #include "patcher.h"
 #include "RoadBlocks.h"
+#include "PathFind.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::Init(void) { EAXJMP(0x436F50); }
 WRAPPER void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); }
-WRAPPER void CRoadBlocks::GenerateRoadBlocks(void) { EAXJMP(0x436FA0); }
\ No newline at end of file
+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 {
+#ifndef MASTER
+                printf("Not enough room for the potential roadblocks\n");
+#endif
+                // FIX: Don't iterate loop after NUMROADBLOCKS
+                return;
+            }
+        }
+    }
+
+}
+
+STARTPATCHES
+	InjectHook(0x436F50, &CRoadBlocks::Init, PATCH_JUMP);
+ENDPATCHES
\ No newline at end of file
diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h
index b1bb3589..3f5868e7 100644
--- a/src/control/RoadBlocks.h
+++ b/src/control/RoadBlocks.h
@@ -6,6 +6,10 @@ class CVehicle;
 class CRoadBlocks
 {
 public:
+	static int16 (&NumRoadBlocks);
+	static int16 (&RoadBlockObjects)[NUMROADBLOCKS];
+	static bool (&InOrOut)[NUMROADBLOCKS];
+
 	static void Init(void);
 	static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16);
 	static void GenerateRoadBlocks(void);
diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp
index 28b4ea6c..4c05e11b 100644
--- a/src/control/SceneEdit.cpp
+++ b/src/control/SceneEdit.cpp
@@ -2,5 +2,10 @@
 #include "patcher.h"
 #include "SceneEdit.h"
 
+int32 &CSceneEdit::m_bCameraFollowActor = *(int*)0x940590;
+bool &CSceneEdit::m_bRecording = *(bool*)0x95CD1F;
+CVector &CSceneEdit::m_vecCurrentPosition = *(CVector*)0x943064;
+CVector &CSceneEdit::m_vecCamHeading = *(CVector*)0x942F8C;
+
 WRAPPER void CSceneEdit::Update(void) { EAXJMP(0x585570); }
 WRAPPER void CSceneEdit::Init(void) { EAXJMP(0x585170); }
diff --git a/src/control/SceneEdit.h b/src/control/SceneEdit.h
index e9209b90..ec321b27 100644
--- a/src/control/SceneEdit.h
+++ b/src/control/SceneEdit.h
@@ -3,6 +3,11 @@
 class CSceneEdit
 {
 public:
+	static int32 &m_bCameraFollowActor;
+	static bool &m_bRecording;
+	static CVector &m_vecCurrentPosition;
+	static CVector &m_vecCamHeading;
+
 	static void Update(void);
 	static void Init(void);
 };
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 42b75554..150b64cd 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS	// for our script loading hack
 #include "common.h"
 #include "patcher.h"
 
diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
new file mode 100644
index 00000000..4ddde360
--- /dev/null
+++ b/src/core/Cam.cpp
@@ -0,0 +1,4424 @@
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "Draw.h"
+#include "World.h"
+#include "Vehicle.h"
+#include "Automobile.h"
+#include "Ped.h"
+#include "PlayerPed.h"
+#include "CopPed.h"
+#include "RpAnimBlend.h"
+#include "ControllerConfig.h"
+#include "Pad.h"
+#include "Frontend.h"
+#include "General.h"
+#include "Renderer.h"
+#include "Shadows.h"
+#include "Hud.h"
+#include "ZoneCull.h"
+#include "SurfaceTable.h"
+#include "WaterLevel.h"
+#include "MBlur.h"
+#include "SceneEdit.h"
+#include "Debug.h"
+#include "Camera.h"
+
+const float DefaultFOV = 70.0f;	// beta: 80.0f
+
+bool PrintDebugCode = false;
+int16 &DebugCamMode = *(int16*)0x95CCF2;
+
+void
+CCam::Init(void)
+{
+	Mode = MODE_FOLLOWPED;
+	Front = CVector(0.0f, 0.0f, -1.0f);
+	Up = CVector(0.0f, 0.0f, 1.0f);
+	Rotating = 0;
+	m_iDoCollisionChecksOnFrameNum = 1;
+	m_iDoCollisionCheckEveryNumOfFrames = 9;
+	m_iFrameNumWereAt = 0;
+	m_bCollisionChecksOn = 1;
+	m_fRealGroundDist = 0.0f;
+	BetaSpeed = 0.0f;
+	AlphaSpeed = 0.0f;
+	DistanceSpeed = 0.0f;
+	f_max_role_angle = DEGTORAD(5.0f);
+	Distance = 30.0f;
+	DistanceSpeed = 0.0f;
+	m_pLastCarEntered = 0;
+	m_pLastPedLookedAt = 0;
+	ResetStatics = 1;
+	Beta = 0.0f;
+	m_bFixingBeta = 0;
+	CA_MIN_DISTANCE = 0.0f;
+	CA_MAX_DISTANCE = 0.0f;
+	LookingBehind = 0;
+	LookingLeft = 0;
+	LookingRight = 0;
+	m_fPlayerInFrontSyphonAngleOffSet = DEGTORAD(20.0f);
+	m_fSyphonModeTargetZOffSet = 0.5f;
+	m_fRadiusForDead = 1.5f;
+	DirectionWasLooking = LOOKING_FORWARD;
+	LookBehindCamWasInFront = 0;
+	f_Roll = 0.0f;
+	f_rollSpeed = 0.0f;
+	m_fCloseInPedHeightOffset = 0.0f;
+	m_fCloseInPedHeightOffsetSpeed = 0.0f;
+	m_fCloseInCarHeightOffset = 0.0f;
+	m_fCloseInCarHeightOffsetSpeed = 0.0f;
+	m_fPedBetweenCameraHeightOffset = 0.0f;
+	m_fTargetBeta = 0.0f;
+	m_fBufferedTargetBeta = 0.0f;
+	m_fBufferedTargetOrientation = 0.0f;
+	m_fBufferedTargetOrientationSpeed = 0.0f;
+	m_fDimensionOfHighestNearCar = 0.0f;
+	m_fRoadOffSet = 0.0f;
+}
+
+void
+CCam::Process(void)
+{
+	CVector CameraTarget;
+	float TargetSpeedVar = 0.0f;
+	float TargetOrientation = 0.0f;
+
+	if(CamTargetEntity == nil)
+		CamTargetEntity = TheCamera.pTargetEntity;
+
+	m_iFrameNumWereAt++;
+	if(m_iFrameNumWereAt > m_iDoCollisionCheckEveryNumOfFrames)
+		m_iFrameNumWereAt = 1;
+	m_bCollisionChecksOn = m_iFrameNumWereAt == m_iDoCollisionChecksOnFrameNum;
+
+	if(m_bCamLookingAtVector){
+		CameraTarget = m_cvecCamFixedModeVector;
+	}else if(CamTargetEntity->IsVehicle()){
+		CameraTarget = CamTargetEntity->GetPosition();
+
+		if(CamTargetEntity->GetForward().x == 0.0f && CamTargetEntity->GetForward().y == 0.0f)
+			TargetOrientation = 0.0f;
+		else
+			TargetOrientation = CGeneral::GetATanOfXY(CamTargetEntity->GetForward().x, CamTargetEntity->GetForward().y);
+
+		CVector Fwd(0.0f, 0.0f, 0.0f);
+		Fwd.x = CamTargetEntity->GetForward().x;
+		Fwd.y = CamTargetEntity->GetForward().y;
+		Fwd.Normalise();
+		// Game normalizes again here manually. useless, so skipped
+
+		float FwdSpeedX = ((CVehicle*)CamTargetEntity)->GetMoveSpeed().x * Fwd.x;
+		float FwdSpeedY = ((CVehicle*)CamTargetEntity)->GetMoveSpeed().y * Fwd.y;
+		if(FwdSpeedX + FwdSpeedY > 0.0f)
+			TargetSpeedVar = min(Sqrt(SQR(FwdSpeedX) + SQR(FwdSpeedY))/0.9f, 1.0f);
+		else
+			TargetSpeedVar = -min(Sqrt(SQR(FwdSpeedX) + SQR(FwdSpeedY))/1.8f, 0.5f);
+		SpeedVar = 0.895f*SpeedVar + 0.105*TargetSpeedVar;
+	}else{
+		CameraTarget = CamTargetEntity->GetPosition();
+
+		if(CamTargetEntity->GetForward().x == 0.0f && CamTargetEntity->GetForward().y == 0.0f)
+			TargetOrientation = 0.0f;
+		else
+			TargetOrientation = CGeneral::GetATanOfXY(CamTargetEntity->GetForward().x, CamTargetEntity->GetForward().y);
+		TargetSpeedVar = 0.0f;
+		SpeedVar = 0.0f;
+	}
+
+	switch(Mode){
+	case MODE_TOPDOWN:
+	case MODE_GTACLASSIC:
+		Process_TopDown(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_BEHINDCAR:
+		Process_BehindCar(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_FOLLOWPED:
+		if(CCamera::m_bUseMouse3rdPerson)
+			Process_FollowPedWithMouse(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		else
+			Process_FollowPed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+//	case MODE_AIMING:
+	case MODE_DEBUG:
+		Process_Debug(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_SNIPER:
+		Process_Sniper(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_ROCKETLAUNCHER:
+		Process_Rocket(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_MODELVIEW:
+		Process_ModelView(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+//	case MODE_BILL:
+	case MODE_SYPHON:
+		Process_Syphon(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_CIRCLE:
+		Process_Circle(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+//	case MODE_CHEESYZOOM:
+	case MODE_WHEELCAM:
+		Process_WheelCam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_FIXED:
+		Process_Fixed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_1STPERSON:
+		Process_1stPerson(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_FLYBY:
+		Process_FlyBy(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_CAM_ON_A_STRING:
+		Process_Cam_On_A_String(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_REACTION:
+		Process_ReactionCam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_FOLLOW_PED_WITH_BIND:
+		Process_FollowPed_WithBinding(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_CHRIS:
+		Process_Chris_With_Binding_PlusRotation(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_BEHINDBOAT:
+		Process_BehindBoat(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_PLAYER_FALLEN_WATER:
+		Process_Player_Fallen_Water(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+//	case MODE_CAM_ON_TRAIN_ROOF:
+//	case MODE_CAM_RUNNING_SIDE_TRAIN:
+//	case MODE_BLOOD_ON_THE_TRACKS:
+//	case MODE_IM_THE_PASSENGER_WOOWOO:
+	case MODE_SYPHON_CRIM_IN_FRONT:
+		Process_Syphon_Crim_In_Front(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_PED_DEAD_BABY:
+		ProcessPedsDeadBaby();
+		break;
+//	case MODE_PILLOWS_PAPS:
+//	case MODE_LOOK_AT_CARS:
+	case MODE_ARRESTCAM_ONE:
+		ProcessArrestCamOne();
+		break;
+	case MODE_ARRESTCAM_TWO:
+		ProcessArrestCamTwo();
+		break;
+	case MODE_M16_1STPERSON:
+	case MODE_HELICANNON_1STPERSON:	// miami
+		Process_M16_1stPerson(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_SPECIAL_FIXED_FOR_SYPHON:
+		Process_SpecialFixedForSyphon(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_FIGHT_CAM:
+		Process_Fight_Cam(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_TOP_DOWN_PED:
+		Process_TopDownPed(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_SNIPER_RUNABOUT:
+	case MODE_ROCKETLAUNCHER_RUNABOUT:
+	case MODE_1STPERSON_RUNABOUT:
+	case MODE_M16_1STPERSON_RUNABOUT:
+	case MODE_FIGHT_CAM_RUNABOUT:
+		Process_1rstPersonPedOnPC(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	case MODE_EDITOR:
+		Process_Editor(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar);
+		break;
+	default:
+		Source = CVector(0.0f, 0.0f, 0.0f);
+		Front = CVector(0.0f, 1.0f, 0.0f);
+		Up = CVector(0.0f, 0.0f, 1.0f);
+	}
+
+	CVector TargetToCam = Source - m_cvecTargetCoorsForFudgeInter;
+	float DistOnGround = TargetToCam.Magnitude2D();
+	m_fTrueBeta = CGeneral::GetATanOfXY(TargetToCam.x, TargetToCam.y);
+	m_fTrueAlpha = CGeneral::GetATanOfXY(TargetToCam.z, DistOnGround);
+	if(TheCamera.m_uiTransitionState == 0)	// TODO? what values are possible? enum?
+		KeepTrackOfTheSpeed(Source, m_cvecTargetCoorsForFudgeInter, Up, m_fTrueAlpha, m_fTrueBeta, FOV);
+
+	// Look Behind, Left, Right
+	LookingBehind = false;
+	LookingLeft = false;
+	LookingRight = false;
+	SourceBeforeLookBehind = Source;
+	if(&TheCamera.Cams[TheCamera.ActiveCam] == this){
+		if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_1STPERSON || Mode == MODE_BEHINDBOAT) &&
+		   CamTargetEntity->IsVehicle()){
+			if(CPad::GetPad(0)->GetLookBehindForCar()){
+				LookBehind();
+				if(DirectionWasLooking != LOOKING_BEHIND)
+					TheCamera.m_bJust_Switched = true;
+				DirectionWasLooking = LOOKING_BEHIND;
+			}else if(CPad::GetPad(0)->GetLookLeft()){
+				LookLeft();
+				if(DirectionWasLooking != LOOKING_LEFT)
+					TheCamera.m_bJust_Switched = true;
+				DirectionWasLooking = LOOKING_LEFT;
+			}else if(CPad::GetPad(0)->GetLookRight()){
+				LookRight();
+				if(DirectionWasLooking != LOOKING_RIGHT)
+					TheCamera.m_bJust_Switched = true;
+				DirectionWasLooking = LOOKING_RIGHT;
+			}else{
+				if(DirectionWasLooking != LOOKING_FORWARD)
+					TheCamera.m_bJust_Switched = true;
+				DirectionWasLooking = LOOKING_FORWARD;
+			}
+		}
+		if(Mode == MODE_FOLLOWPED && CamTargetEntity->IsPed()){
+			if(CPad::GetPad(0)->GetLookBehindForPed()){
+				LookBehind();
+				if(DirectionWasLooking != LOOKING_BEHIND)
+					TheCamera.m_bJust_Switched = true;
+				DirectionWasLooking = LOOKING_BEHIND;
+			}else
+				DirectionWasLooking = LOOKING_FORWARD;
+		}
+	}
+
+	if(Mode == MODE_SNIPER || Mode == MODE_ROCKETLAUNCHER || Mode == MODE_M16_1STPERSON ||
+	   Mode == MODE_1STPERSON || Mode == MODE_HELICANNON_1STPERSON || GetWeaponFirstPersonOn())
+		ClipIfPedInFrontOfPlayer();
+}
+
+// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms
+// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms
+void
+WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle)
+{
+	float Delta = Target - *CurrentValue;
+
+	if(IsAngle){
+		while(Delta >= PI) Delta -= 2*PI;
+		while(Delta < -PI) Delta += 2*PI;
+	}
+
+	float TargetSpeed = Delta * MaxSpeed;
+	// Add or subtract absolute depending on sign, genius!
+//	if(TargetSpeed - *CurrentSpeed > 0.0f)
+//		*CurrentSpeed += Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
+//	else
+//		*CurrentSpeed -= Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
+	// this is simpler:
+	*CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
+
+	// Clamp speed if we overshot
+	if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed)
+		*CurrentSpeed = TargetSpeed;
+	else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed)
+		*CurrentSpeed = TargetSpeed;
+
+	*CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep());
+}
+
+void
+MakeAngleLessThan180(float &Angle)
+{
+	while(Angle >= PI) Angle -= 2*PI;
+	while(Angle < -PI) Angle += 2*PI;
+}
+
+void
+CCam::ProcessSpecialHeightRoutines(void)
+{
+	int i = 0;
+	bool StandingOnBoat = false;
+	static bool PreviouslyFailedRoadHeightCheck = false;
+	CVector CamToTarget, CamToPed;
+	float DistOnGround, BetaAngle;
+	CPed *Player;
+	int ClosestPed = 0;
+	bool FoundPed = false;
+	float ClosestPedDist, PedZDist;
+	CColPoint colPoint;
+
+	CamToTarget = TheCamera.pTargetEntity->GetPosition() - TheCamera.GetGameCamPosition();
+	DistOnGround = CamToTarget.Magnitude2D();
+	BetaAngle = CGeneral::GetATanOfXY(CamToTarget.x, CamToTarget.y);
+	m_bTheHeightFixerVehicleIsATrain = false;
+	ClosestPedDist = 0.0f;
+	// CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y);
+	Player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+
+	if(DistOnGround > 10.0f)
+		DistOnGround = 10.0f;
+
+	if(CamTargetEntity && CamTargetEntity->IsPed()){
+		if(FindPlayerPed()->m_pCurSurface && FindPlayerPed()->m_pCurSurface->IsVehicle() &&
+		   ((CVehicle*)FindPlayerPed()->m_pCurSurface)->IsBoat())
+			StandingOnBoat = true;
+
+		// Move up the camera if there is a ped close to it
+		if(Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM){
+			// Find ped closest to camera
+			while(i < Player->m_numNearPeds){
+				if(Player->m_nearPeds[i] && Player->m_nearPeds[i]->GetPedState() != PED_DEAD){
+					CamToPed = Player->m_nearPeds[i]->GetPosition() - TheCamera.GetGameCamPosition();
+					if(FoundPed){
+						if(CamToPed.Magnitude2D() < ClosestPedDist){
+							ClosestPed = i;
+							ClosestPedDist = CamToPed.Magnitude2D();
+						}
+					}else{
+						FoundPed = true;
+						ClosestPed = i;
+						ClosestPedDist = CamToPed.Magnitude2D();
+					}
+				}
+				i++;
+			}
+
+			if(FoundPed){
+				float Offset = 0.0f;
+				CPed *Ped = Player->m_nearPeds[ClosestPed];
+				CamToPed = Ped->GetPosition() - TheCamera.GetGameCamPosition();
+				PedZDist = 0.0f;
+				float dist = CamToPed.Magnitude2D();	// should be same as ClosestPedDist
+				if(dist < 2.1f){
+					// Ped is close to camera, move up
+
+					// Z Distance between player and close ped
+					PedZDist = 0.0f;
+					if(Ped->bIsStanding)
+						PedZDist = Ped->GetPosition().z - Player->GetPosition().z;
+					// Ignore if too distant
+					if(PedZDist > 1.2f || PedZDist < -1.2f)
+						PedZDist = 0.0f;
+
+					float DistScale = (2.1f - dist)/2.1f;
+					if(Mode == MODE_FOLLOWPED){
+						if(TheCamera.PedZoomIndicator == 1.0f)
+							Offset = 0.45*DistScale + PedZDist;
+						if(TheCamera.PedZoomIndicator == 2.0f)
+							Offset = 0.35*DistScale + PedZDist;
+						if(TheCamera.PedZoomIndicator == 3.0f)
+							Offset = 0.25*DistScale + PedZDist;
+						if(Abs(CGeneral::GetRadianAngleBetweenPoints(CamToPed.x, CamToPed.y, CamToTarget.x, CamToTarget.y)) > HALFPI)
+							Offset += 0.3f;
+						m_fPedBetweenCameraHeightOffset = Offset + 1.3f;
+						PedZDist = 0.0f;
+					}else if(Mode == MODE_FIGHT_CAM)
+						m_fPedBetweenCameraHeightOffset = PedZDist + 1.3f + 0.5f;
+				}else
+					m_fPedBetweenCameraHeightOffset = 0.0f;
+			}else{
+				PedZDist = 0.0f;
+				m_fPedBetweenCameraHeightOffset = 0.0f;
+			}
+		}else
+			PedZDist = 0.0f;
+
+
+		// Move camera up for vehicles in the way
+		if(m_bCollisionChecksOn && (Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM)){
+			bool FoundCar = false;
+			CEntity *vehicle = nil;
+			float TestDist = DistOnGround + 1.25f;
+			float HighestCar = 0.0f;
+			CVector TestBase = CamTargetEntity->GetPosition();
+			CVector TestPoint;
+			TestBase.z -= 0.15f;
+
+			TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle), Sin(BetaAngle), 0.0f);
+			if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) &&
+			   vehicle->IsVehicle()){
+				float height = vehicle->GetColModel()->boundingBox.GetSize().z;
+				FoundCar = true;
+				HighestCar = height;
+				if(((CVehicle*)vehicle)->IsTrain())
+					m_bTheHeightFixerVehicleIsATrain = true;
+			}
+
+			TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle+DEGTORAD(28.0f)), Sin(BetaAngle+DEGTORAD(28.0f)), 0.0f);
+			if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) &&
+			   vehicle->IsVehicle()){
+				float height = vehicle->GetColModel()->boundingBox.GetSize().z;
+				if(FoundCar){
+					HighestCar = max(HighestCar, height);
+				}else{
+					FoundCar = true;
+					HighestCar = height;
+				}
+				if(((CVehicle*)vehicle)->IsTrain())
+					m_bTheHeightFixerVehicleIsATrain = true;
+			}
+
+			TestPoint = TestBase - TestDist * CVector(Cos(BetaAngle-DEGTORAD(28.0f)), Sin(BetaAngle-DEGTORAD(28.0f)), 0.0f);
+			if(CWorld::ProcessLineOfSight(CamTargetEntity->GetPosition(), TestPoint, colPoint, vehicle, false, true, false, false, false, false) &&
+			   vehicle->IsVehicle()){
+				float height = vehicle->GetColModel()->boundingBox.GetSize().z;
+				if(FoundCar){
+					HighestCar = max(HighestCar, height);
+				}else{
+					FoundCar = true;
+					HighestCar = height;
+				}
+				if(((CVehicle*)vehicle)->IsTrain())
+					m_bTheHeightFixerVehicleIsATrain = true;
+			}
+
+			if(FoundCar){
+				m_fDimensionOfHighestNearCar = HighestCar + 0.1f;
+				if(Mode == MODE_FIGHT_CAM)
+					m_fDimensionOfHighestNearCar += 0.75f;
+			}else
+				m_fDimensionOfHighestNearCar = 0.0f;
+		}
+
+		// Move up for road
+		if(Mode == MODE_FOLLOWPED || Mode == MODE_FIGHT_CAM ||
+		   Mode == MODE_SYPHON || Mode == MODE_SYPHON_CRIM_IN_FRONT || Mode == MODE_SPECIAL_FIXED_FOR_SYPHON){
+			bool Inside = false;
+			bool OnRoad = false;
+
+			switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched)
+			case SURFACE_GRASS:
+			case SURFACE_DIRT:
+			case SURFACE_DIRTTRACK:
+			case SURFACE_STEEL:
+			case SURFACE_TIRE:
+			case SURFACE_STONE:
+				OnRoad = true;
+
+			if(CCullZones::PlayerNoRain())
+				Inside = true;
+
+			if((m_bCollisionChecksOn || PreviouslyFailedRoadHeightCheck || OnRoad) &&
+			   m_fCloseInPedHeightOffset < 0.0001f && !Inside){
+				CVector TestPoint;
+				CEntity *road;
+				float GroundZ = 0.0f;
+				bool FoundGround = false;
+				float RoofZ = 0.0f;
+				bool FoundRoof = false;
+				static float MinHeightAboveRoad = 0.9f;
+
+				TestPoint = CamTargetEntity->GetPosition() - DistOnGround * CVector(Cos(BetaAngle), Sin(BetaAngle), 0.0f);
+				m_fRoadOffSet = 0.0f;
+
+				if(CWorld::ProcessVerticalLine(TestPoint, -1000.0f, colPoint, road, true, false, false, false, false, false, nil)){
+					FoundGround = true;
+					GroundZ = colPoint.point.z;
+				}
+				// Move up if too close to ground
+				if(FoundGround){
+					if(TestPoint.z - GroundZ < MinHeightAboveRoad){
+						m_fRoadOffSet = GroundZ + MinHeightAboveRoad - TestPoint.z;
+						PreviouslyFailedRoadHeightCheck = true;
+					}else{
+						if(m_bCollisionChecksOn)
+							PreviouslyFailedRoadHeightCheck = false;
+						else
+							m_fRoadOffSet = 0.0f;
+					}
+				}else{
+					if(CWorld::ProcessVerticalLine(TestPoint, 1000.0f, colPoint, road, true, false, false, false, false, false, nil)){
+						FoundRoof = true;
+						RoofZ = colPoint.point.z;
+					}
+					if(FoundRoof){
+						if(TestPoint.z - RoofZ < MinHeightAboveRoad){
+							m_fRoadOffSet = RoofZ + MinHeightAboveRoad - TestPoint.z;
+							PreviouslyFailedRoadHeightCheck = true;
+						}else{
+							if(m_bCollisionChecksOn)
+								PreviouslyFailedRoadHeightCheck = false;
+							else
+								m_fRoadOffSet = 0.0f;
+						}
+					}
+				}
+			}
+		}
+
+		if(PreviouslyFailedRoadHeightCheck && m_fCloseInPedHeightOffset < 0.0001f){
+			if(colPoint.surfaceB != SURFACE_TARMAC &&
+			   colPoint.surfaceB != SURFACE_GRASS &&
+			   colPoint.surfaceB != SURFACE_DIRT &&
+			   colPoint.surfaceB != SURFACE_DIRTTRACK &&
+			   colPoint.surfaceB != SURFACE_STONE){
+				if(m_fRoadOffSet > 1.4f)
+					m_fRoadOffSet = 1.4f;
+			}else{
+				if(Mode == MODE_FOLLOWPED){
+					if(TheCamera.PedZoomIndicator == 1.0f)
+						m_fRoadOffSet += 0.2f;
+					if(TheCamera.PedZoomIndicator == 2.0f)
+						m_fRoadOffSet += 0.5f;
+					if(TheCamera.PedZoomIndicator == 3.0f)
+						m_fRoadOffSet += 0.95f;
+				}
+			}
+		}
+	}
+
+	if(StandingOnBoat){
+		m_fRoadOffSet = 0.0f;
+		m_fDimensionOfHighestNearCar = 1.0f;
+		m_fPedBetweenCameraHeightOffset = 0.0f;
+	}
+}
+
+void
+CCam::GetVectorsReadyForRW(void)
+{
+	CVector right;
+	Up = CVector(0.0f, 0.0f, 1.0f);
+	Front.Normalise();
+	if(Front.x == 0.0f && Front.y == 0.0f){
+		Front.x = 0.0001f;
+		Front.y = 0.0001f;
+	}
+	right = CrossProduct(Front, Up);
+	right.Normalise();
+	Up = CrossProduct(right, Front);
+}
+
+void
+CCam::LookBehind(void)
+{
+	float Dist, DeltaBeta, TargetOrientation, Angle;
+	CVector TargetCoors, TargetFwd, TestCoors;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	TargetCoors = CamTargetEntity->GetPosition();
+	Front = CamTargetEntity->GetPosition() - Source;
+
+	if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){
+		LookingBehind = true;
+		Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 15.5f;
+		TargetFwd = CamTargetEntity->GetForward();
+		TargetFwd.Normalise();
+		TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y);
+		DeltaBeta = TargetOrientation - Beta;
+		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+		if(DirectionWasLooking == LOOKING_BEHIND)
+			LookBehindCamWasInFront = DeltaBeta <= -HALFPI || DeltaBeta >= HALFPI;
+		if(LookBehindCamWasInFront)
+			TargetOrientation += PI;
+		Source.x = Dist*Cos(TargetOrientation) + TargetCoors.x;
+		Source.y = Dist*Sin(TargetOrientation) + TargetCoors.y;
+		Source.z -= 1.0f;
+		if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+			RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+			Source = colPoint.point;
+		}
+		Source.z += 1.0f;
+		Front = CamTargetEntity->GetPosition() - Source;
+		GetVectorsReadyForRW();
+	}
+	if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){
+		LookingBehind = true;
+		RwCameraSetNearClipPlane(Scene.camera, 0.25f);
+		Front = CamTargetEntity->GetForward();
+		Front.Normalise();
+		if(((CVehicle*)CamTargetEntity)->IsBoat())
+			Source.z -= 0.5f;
+		Source += 0.25f*Front;
+		Front = -Front;
+#ifdef FIX_BUGS
+		// not sure if this is a bug...
+		GetVectorsReadyForRW();
+#endif
+	}
+	if(CamTargetEntity->IsPed()){
+		Angle = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y) + PI;
+		Source.x = 4.5f*Cos(Angle) + TargetCoors.x;
+		Source.y = 4.5f*Sin(Angle) + TargetCoors.y;
+		Source.z = 1.15f + TargetCoors.z;
+		TestCoors = TargetCoors;
+		TestCoors.z = Source.z;
+		if(CWorld::ProcessLineOfSight(TestCoors, Source, colPoint, entity, true, true, false, true, false, true, true)){
+			Source.x = colPoint.point.x;
+			Source.y = colPoint.point.y;
+			if((TargetCoors - Source).Magnitude2D() < 1.15f)
+				RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+		}
+		Front = TargetCoors - Source;
+		GetVectorsReadyForRW();
+	}
+}
+
+void
+CCam::LookLeft(void)
+{
+	float Dist, TargetOrientation;
+	CVector TargetCoors, TargetFwd;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){
+		LookingLeft = true;
+		TargetCoors = CamTargetEntity->GetPosition();
+		Front = CamTargetEntity->GetPosition() - Source;
+		Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 9.0f;
+		TargetFwd = CamTargetEntity->GetForward();
+		TargetFwd.Normalise();
+		TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y);
+		Source.x = Dist*Cos(TargetOrientation - HALFPI) + TargetCoors.x;
+		Source.y = Dist*Sin(TargetOrientation - HALFPI) + TargetCoors.y;
+		Source.z -= 1.0f;
+		if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+			RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+			Source = colPoint.point;
+		}
+		Source.z += 1.0f;
+		Front = CamTargetEntity->GetPosition() - Source;
+		Front.z += 1.1f;
+		if(Mode == MODE_BEHINDBOAT)
+			Front.z += 1.2f;
+		GetVectorsReadyForRW();
+	}
+	if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){
+		LookingLeft = true;
+		RwCameraSetNearClipPlane(Scene.camera, 0.25f);
+		if(((CVehicle*)CamTargetEntity)->IsBoat())
+			Source.z -= 0.5f;
+
+		Up = CamTargetEntity->GetUp();
+		Up.Normalise();
+		Front = CamTargetEntity->GetForward();
+		Front.Normalise();
+		Front = -CrossProduct(Front, Up);
+		Front.Normalise();
+#ifdef FIX_BUGS
+		// not sure if this is a bug...
+		GetVectorsReadyForRW();
+#endif
+	}
+}
+
+void
+CCam::LookRight(void)
+{
+	float Dist, TargetOrientation;
+	CVector TargetCoors, TargetFwd;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	if((Mode == MODE_CAM_ON_A_STRING || Mode == MODE_BEHINDBOAT) && CamTargetEntity->IsVehicle()){
+		LookingRight = true;
+		TargetCoors = CamTargetEntity->GetPosition();
+		Front = CamTargetEntity->GetPosition() - Source;
+		Dist = Mode == MODE_CAM_ON_A_STRING ? CA_MAX_DISTANCE : 9.0f;
+		TargetFwd = CamTargetEntity->GetForward();
+		TargetFwd.Normalise();
+		TargetOrientation = CGeneral::GetATanOfXY(TargetFwd.x, TargetFwd.y);
+		Source.x = Dist*Cos(TargetOrientation + HALFPI) + TargetCoors.x;
+		Source.y = Dist*Sin(TargetOrientation + HALFPI) + TargetCoors.y;
+		Source.z -= 1.0f;
+		if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+			RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+			Source = colPoint.point;
+		}
+		Source.z += 1.0f;
+		Front = CamTargetEntity->GetPosition() - Source;
+		Front.z += 1.1f;
+		if(Mode == MODE_BEHINDBOAT)
+			Front.z += 1.2f;
+		GetVectorsReadyForRW();
+	}
+	if(Mode == MODE_1STPERSON && CamTargetEntity->IsVehicle()){
+		LookingRight = true;
+		RwCameraSetNearClipPlane(Scene.camera, 0.25f);
+		if(((CVehicle*)CamTargetEntity)->IsBoat())
+			Source.z -= 0.5f;
+
+		Up = CamTargetEntity->GetUp();
+		Up.Normalise();
+		Front = CamTargetEntity->GetForward();
+		Front.Normalise();
+		Front = CrossProduct(Front, Up);
+		Front.Normalise();
+#ifdef FIX_BUGS
+		// not sure if this is a bug...
+		GetVectorsReadyForRW();
+#endif
+	}
+}
+
+void
+CCam::ClipIfPedInFrontOfPlayer(void)
+{
+	float FwdAngle, PedAngle, DeltaAngle, fDist, Near;
+	CVector vDist;
+	CPed *Player;
+	bool found = false;
+	int ped = 0;
+
+	// unused: TheCamera.pTargetEntity->GetPosition() - TheCamera.GetGameCamPosition();
+
+	FwdAngle = CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y);
+	Player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+	while(ped < Player->m_numNearPeds && !found)
+		if(Player->m_nearPeds[ped] && Player->m_nearPeds[ped]->GetPedState() != PED_DEAD)
+			found = true;
+		else
+			ped++;
+	if(found){
+		vDist = Player->m_nearPeds[ped]->GetPosition() - TheCamera.GetGameCamPosition();
+		PedAngle = CGeneral::GetATanOfXY(vDist.x, vDist.y);
+		DeltaAngle = FwdAngle - PedAngle;
+		while(DeltaAngle >= PI) DeltaAngle -= 2*PI;
+		while(DeltaAngle < -PI) DeltaAngle += 2*PI;
+		if(Abs(DeltaAngle) < HALFPI){
+			fDist = Sqrt(SQR(vDist.x) + SQR(vDist.y));
+			if(fDist < 1.25f){
+				Near = 0.9f - (1.25f - fDist);
+				if(Near < 0.05f)
+					Near = 0.05f;
+				RwCameraSetNearClipPlane(Scene.camera, Near);
+			}
+		}
+	}
+}
+
+void
+CCam::KeepTrackOfTheSpeed(const CVector &source, const CVector &target, const CVector &up, const float &alpha, const float &beta, const float &fov)
+{
+	static CVector PreviousSource = source;
+	static CVector PreviousTarget = target;
+	static CVector PreviousUp = up;
+	static float PreviousBeta = beta;
+	static float PreviousAlpha = alpha;
+	static float PreviousFov = fov;
+
+	if(TheCamera.m_bJust_Switched){
+		PreviousSource = source;
+		PreviousTarget = target;
+		PreviousUp = up;
+	}
+
+	m_cvecSourceSpeedOverOneFrame = PreviousSource - source;
+	m_cvecTargetSpeedOverOneFrame = PreviousTarget - target;
+	m_cvecUpOverOneFrame = PreviousUp - up;
+	m_fFovSpeedOverOneFrame = fov - PreviousFov;
+	m_fBetaSpeedOverOneFrame = beta - PreviousBeta;
+	MakeAngleLessThan180(m_fBetaSpeedOverOneFrame);
+	m_fAlphaSpeedOverOneFrame = alpha - PreviousAlpha;
+	MakeAngleLessThan180(m_fAlphaSpeedOverOneFrame);
+
+	PreviousSource = source;
+	PreviousTarget = target;
+	PreviousUp = up;
+	PreviousBeta = beta;
+	PreviousAlpha = alpha;
+	PreviousFov = fov;
+}
+
+bool
+CCam::Using3rdPersonMouseCam(void) 
+{
+	return CCamera::m_bUseMouse3rdPerson &&
+		(Mode == MODE_FOLLOWPED ||
+			TheCamera.m_bPlayerIsInGarage &&
+			FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING &&
+			Mode != MODE_TOPDOWN && this->CamTargetEntity == FindPlayerPed());
+}
+
+bool
+CCam::GetWeaponFirstPersonOn(void)
+{
+	CEntity *target = this->CamTargetEntity;
+	if (target && target->IsPed())
+		return ((CPed*)target)->GetWeapon()->m_bAddRotOffset;
+	
+	return false;
+}
+
+bool
+CCam::IsTargetInWater(const CVector &CamCoors)
+{
+	if(CamTargetEntity == nil)
+		return false;
+	if(CamTargetEntity->IsPed()){
+		if(!((CPed*)CamTargetEntity)->bIsInWater)
+			return false;
+		if(!((CPed*)CamTargetEntity)->bIsStanding)
+			return true;
+		return false;
+	}
+	return ((CPhysical*)CamTargetEntity)->bIsInWater;
+}
+
+void
+CCam::PrintMode(void)
+{
+	// Doesn't do anything
+	char buf[256];
+
+	if(PrintDebugCode){
+		sprintf(buf, "                                                   ");
+		sprintf(buf, "                                                   ");
+		sprintf(buf, "                                                   ");
+
+		static char *modes[] = { "None",
+			"Top Down", "GTA Classic", "Behind Car", "Follow Ped",
+			"Aiming", "Debug", "Sniper", "Rocket", "Model Viewer", "Bill",
+			"Syphon", "Circle", "Cheesy Zoom", "Wheel", "Fixed",
+			"1st Person", "Fly by", "on a String", "Reaction",
+			"Follow Ped with Bind", "Chris", "Behind Boat",
+			"Player fallen in Water", "Train Roof", "Train Side",
+			"Blood on the tracks", "Passenger", "Syphon Crim in Front",
+			"Dead Baby", "Pillow Paps", "Look at Cars", "Arrest One",
+			"Arrest Two", "M16", "Special fixed for Syphon", "Fight",
+			"Top Down Ped",
+			"Sniper run about", "Rocket run about",
+			"1st Person run about", "M16 run about", "Fight run about",
+			"Editor"
+		};
+		sprintf(buf, "Cam: %s", modes[TheCamera.Cams[TheCamera.ActiveCam].Mode]);
+		CDebug::PrintAt(buf, 2, 5);
+	}
+
+	if(DebugCamMode != MODE_NONE){
+		switch(Mode){
+		case MODE_FOLLOWPED:
+			sprintf(buf, "Debug:- Cam Choice1. No Locking, used as game default");
+			break;
+		case MODE_REACTION:
+			sprintf(buf, "Debug:- Cam Choice2. Reaction Cam On A String ");
+			sprintf(buf, "        Uses Locking Button LeftShoulder 1. ");	// lie
+			break;
+		case MODE_FOLLOW_PED_WITH_BIND:
+			sprintf(buf, "Debug:- Cam Choice3. Game ReactionCam with Locking ");
+			sprintf(buf, "        Uses Locking Button LeftShoulder 1. ");
+			break;
+		case MODE_CHRIS:
+			sprintf(buf, "Debug:- Cam Choice4. Chris's idea.  ");
+			sprintf(buf, "        Uses Locking Button LeftShoulder 1. ");
+			sprintf(buf, "        Also control the camera using the right analogue stick.");
+			break;
+		}
+	}
+}
+
+// This code is really bad. wtf R*?
+CVector
+CCam::DoAverageOnVector(const CVector &vec)
+{
+	int i;
+	CVector Average = { 0.0f, 0.0f, 0.0f };
+
+	if(ResetStatics){
+		m_iRunningVectorArrayPos = 0;
+		m_iRunningVectorCounter = 1;
+	}
+
+	// TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2
+	if(m_iRunningVectorCounter == 3){
+		m_arrPreviousVectors[0] = m_arrPreviousVectors[1];
+		m_arrPreviousVectors[1] = vec;
+	}else
+		m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec;
+
+	for(i = 0; i <= m_iRunningVectorArrayPos; i++)
+		Average += m_arrPreviousVectors[i];
+	Average /= i;
+
+	m_iRunningVectorArrayPos++;
+	m_iRunningVectorCounter++;
+	if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE)
+		m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1;
+	if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1)
+		m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1;
+
+	return Average;
+}
+
+// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps.
+// Return the first angle for which Beta + BetaOffset + Angle has a clear view.
+// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear.
+// If BetaOffset == 0, try both directions.
+float
+CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
+{
+	CColPoint point;
+	CEntity *ent = nil;
+	CVector ToSource;
+	float a;
+
+	// This would be so much nicer if we just got the step variable before the loop...R*
+
+	for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){
+		if(BetaOffset <= 0.0f){
+			ToSource = CVector(Cos(Beta + BetaOffset + a), Sin(Beta + BetaOffset + a), 0.0f)*Dist;
+			if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
+						point, ent, checkBuildings, checkVehicles, checkPeds,
+						checkObjects, checkDummies, true, true))
+				return a;
+		}
+		if(BetaOffset >= 0.0f){
+			ToSource = CVector(Cos(Beta + BetaOffset - a), Sin(Beta + BetaOffset - a), 0.0f)*Dist;
+			if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
+						point, ent, checkBuildings, checkVehicles, checkPeds,
+						checkObjects, checkDummies, true, true))
+				return -a;
+		}
+	}
+	return 0.0f;
+}
+
+static float DefaultAcceleration = 0.045f;
+static float DefaultMaxStep = 0.15f;
+
+void
+CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	const float GroundDist = 1.85f;
+
+	CVector TargetCoors, Dist, IdealSource;
+	float Length = 0.0f;
+	float LateralLeft = 0.0f;
+	float LateralRight = 0.0f;
+	float Center = 0.0f;
+	static bool PreviouslyObscured;
+	static bool PickedASide;
+	static float FixedTargetOrientation = 0.0f;
+	float AngleToGoTo = 0.0f;
+	float BetaOffsetAvoidBuildings = 0.45f;		// ~25 deg
+	float BetaOffsetGoingBehind = 0.45f;
+	bool GoingBehind = false;
+	bool Obscured = false;
+	bool BuildingCheckObscured = false;
+	bool HackPlayerOnStoppingTrain = false;
+	static int TimeIndicatedWantedToGoDown = 0;
+	static bool StartedCountingForGoDown = false;
+	float DeltaBeta;
+
+	m_bFixingBeta = false;
+	bBelowMinDist = false;
+	bBehindPlayerDesired = false;
+
+#ifdef FIX_BUGS
+	if(!CamTargetEntity->IsPed())
+		return;
+#endif
+	assert(CamTargetEntity->IsPed());
+
+	// CenterDist should be > LateralDist because we don't have an angle for safety in this case
+	float CenterDist, LateralDist;
+	float AngleToGoToSpeed;
+	if(m_fCloseInPedHeightOffset > 0.00001f){
+		LateralDist = 0.55f;
+		CenterDist = 1.25f;
+		BetaOffsetAvoidBuildings = 0.9f;	// ~50 deg
+		BetaOffsetGoingBehind = 0.9f;
+		AngleToGoToSpeed = 0.88254666f;
+	}else{
+		LateralDist = 0.8f;
+		CenterDist = 1.35f;
+		if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){
+			LateralDist = 1.25f;
+			CenterDist = 1.6f;
+		}
+		AngleToGoToSpeed = 0.43254671f;
+	}
+
+	FOV = DefaultFOV;
+
+	if(ResetStatics){
+		Rotating = false;
+		m_bCollisionChecksOn = true;
+		FixedTargetOrientation = 0.0f;
+		PreviouslyObscured = false;
+		PickedASide = false;
+		StartedCountingForGoDown = false;
+		AngleToGoTo = 0.0f;
+		// unused LastAngleWithNoPickedASide
+	}
+
+
+	TargetCoors = CameraTarget;
+	IdealSource = Source;
+	TargetCoors.z += m_fSyphonModeTargetZOffSet;
+
+	TargetCoors = DoAverageOnVector(TargetCoors);
+	TargetCoors.z += m_fRoadOffSet;
+
+	Dist.x = IdealSource.x - TargetCoors.x;
+	Dist.y = IdealSource.y - TargetCoors.y;
+	Length = Dist.Magnitude2D();
+
+	// Cam on a string. With a fixed distance. Zoom in/out is done later.
+	if(Length != 0.0f)
+		IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist;
+	else
+		IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f);
+
+	// TODO: what's transition beta?
+	if(TheCamera.m_bUseTransitionBeta && ResetStatics){
+		CVector VecDistance;
+		IdealSource.x = TargetCoors.x + GroundDist*Cos(m_fTransitionBeta);
+		IdealSource.y = TargetCoors.y + GroundDist*Sin(m_fTransitionBeta);
+		Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y);
+	}else
+		Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
+
+	if(TheCamera.m_bCamDirectlyBehind){
+		 m_bCollisionChecksOn = true;
+		 Beta = TargetOrientation + PI;
+	}
+
+	if(FindPlayerVehicle())
+		if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN)
+			HackPlayerOnStoppingTrain = true;
+
+	if(TheCamera.m_bCamDirectlyInFront){
+		 m_bCollisionChecksOn = true;
+		 Beta = TargetOrientation;
+	}
+
+	while(Beta >= PI) Beta -= 2.0f * PI;
+	while(Beta < -PI) Beta += 2.0f * PI;
+
+	// BUG? is this ever used?
+	// The values seem to be roughly m_fPedZoomValueSmooth + 1.85
+	if(ResetStatics){
+		if(TheCamera.PedZoomIndicator == 1.0) m_fRealGroundDist = 2.090556f;
+		if(TheCamera.PedZoomIndicator == 2.0) m_fRealGroundDist = 3.34973f;
+		if(TheCamera.PedZoomIndicator == 3.0) m_fRealGroundDist = 4.704914f;
+		if(TheCamera.PedZoomIndicator == 4.0) m_fRealGroundDist = 2.090556f;
+	}
+	// And what is this? It's only used for collision and rotation it seems
+	float RealGroundDist;
+	if(TheCamera.PedZoomIndicator == 1.0) RealGroundDist = 2.090556f;
+	if(TheCamera.PedZoomIndicator == 2.0) RealGroundDist = 3.34973f;
+	if(TheCamera.PedZoomIndicator == 3.0) RealGroundDist = 4.704914f;
+	if(TheCamera.PedZoomIndicator == 4.0) RealGroundDist = 2.090556f;
+	if(m_fCloseInPedHeightOffset >  0.00001f)
+		RealGroundDist = 1.7016f;
+
+
+	bool Shooting = false;
+	CPed *ped = (CPed*)CamTargetEntity;
+	if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
+		if(CPad::GetPad(0)->GetWeapon())
+			Shooting = true;
+	if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR ||
+	   ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT)
+		Shooting = false;
+
+
+	if(m_fCloseInPedHeightOffset > 0.00001f)
+		TargetCoors.z -= m_fRoadOffSet;
+
+	// Figure out if and where we want to rotate
+
+	if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
+
+		// Center cam behind player
+
+		GoingBehind = true;
+		m_bCollisionChecksOn = true;
+		float OriginalBeta = Beta;
+		// Set Beta behind player
+		Beta = TargetOrientation + PI;
+		TargetCoors.z -= 0.1f;
+
+		AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
+		if(AngleToGoTo != 0.0f){
+			if(AngleToGoTo < 0.0f)
+				AngleToGoTo -= AngleToGoToSpeed;
+			else
+				AngleToGoTo += AngleToGoToSpeed;
+		}else{
+			float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false);
+			float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false);
+			if(LateralLeft == 0.0f && LateralRight != 0.0f)
+				AngleToGoTo += LateralRight;
+			else if(LateralLeft != 0.0f && LateralRight == 0.0f)
+				AngleToGoTo += LateralLeft;
+		}
+
+		TargetCoors.z += 0.1f;
+		Beta = OriginalBeta;
+
+		if(PickedASide){
+			if(AngleToGoTo == 0.0f)
+				FixedTargetOrientation = TargetOrientation + PI;
+			Rotating = true;
+		}else{
+			FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo;
+			Rotating = true;
+			PickedASide = true;
+		}
+	}else{
+
+		// Rotate cam to avoid clipping into buildings
+
+		TargetCoors.z -= 0.1f;
+
+		Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
+		if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){
+			if(Center != 0.0f){
+				AngleToGoTo = Center;
+			}else{
+				LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false);
+				LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false);
+				if(LateralLeft == 0.0f && LateralRight != 0.0f){
+					AngleToGoTo += LateralRight;
+					if(m_fCloseInPedHeightOffset > 0.0f)
+						RwCameraSetNearClipPlane(Scene.camera, 0.7f);
+				}else if(LateralLeft != 0.0f && LateralRight == 0.0f){
+					AngleToGoTo += LateralLeft;
+					if(m_fCloseInPedHeightOffset > 0.0f)
+						RwCameraSetNearClipPlane(Scene.camera, 0.7f);
+				}
+			}
+			if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f)
+				BuildingCheckObscured = true;
+		}
+
+		TargetCoors.z += 0.1f;
+	}
+
+	if(m_fCloseInPedHeightOffset > 0.00001f)
+		TargetCoors.z += m_fRoadOffSet;
+
+
+	// Have to fix to avoid collision
+
+	if(AngleToGoTo != 0.0f){
+		Obscured = true;
+		Rotating = true;
+		if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
+			if(!PickedASide)
+				FixedTargetOrientation = Beta + AngleToGoTo;	// can this even happen?
+		}else
+			FixedTargetOrientation = Beta + AngleToGoTo;
+
+		// This calculation is only really used to figure out how fast to rotate out of collision
+
+		m_fAmountFractionObscured = 1.0f;
+		CVector PlayerPos = FindPlayerPed()->GetPosition();
+		float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist;
+		// What's going on here? - AngleToGoTo?
+		CVector RotatedSource = PlayerPos + CVector(Cos(Beta - AngleToGoTo), Sin(Beta - AngleToGoTo), 0.0f) * RotationDist;
+
+		CColPoint colpoint;
+		CEntity *entity;
+		if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){
+			if((PlayerPos - RotatedSource).Magnitude() != 0.0f)
+				m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude();
+			else
+				m_fAmountFractionObscured = 1.0f;
+		}
+	}
+	if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f;
+	if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f;
+
+
+
+	// Figure out speed values for Beta rotation
+
+	float Acceleration, MaxSpeed;
+	static float AccelerationMult = 0.35f;
+	static float MaxSpeedMult = 0.85f;
+	static float AccelerationMultClose = 0.7f;
+	static float MaxSpeedMultClose = 1.6f;
+	float BaseAcceleration = 0.025f;
+	float BaseMaxSpeed = 0.09f;
+	if(m_fCloseInPedHeightOffset > 0.00001f){
+		if(AngleToGoTo == 0.0f){
+			BaseAcceleration = 0.022f;
+			BaseMaxSpeed = 0.04f;
+		}else{
+			BaseAcceleration = DefaultAcceleration;
+			BaseMaxSpeed = DefaultMaxStep;
+		}
+	}
+	if(AngleToGoTo == 0.0f){
+		Acceleration = BaseAcceleration;
+		MaxSpeed = BaseMaxSpeed;
+	}else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){
+		Acceleration = 0.051f;
+		MaxSpeed = 0.18f;
+	}else if(m_fCloseInPedHeightOffset > 0.00001f){
+		Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f);
+		MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f);
+	}else{
+		Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f);
+		MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f);
+	}
+	static float AccelerationLimit = 0.3f;
+	static float MaxSpeedLimit = 0.65f;
+	if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit;
+	if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit;
+
+
+	int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState;
+	if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL &&
+	   !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){
+		Rotating = false;
+		BetaSpeed = 0.0f;
+	}
+
+	// Now do the Beta rotation
+
+	float Distance = (IdealSource - TargetCoors).Magnitude2D();
+	m_fDistanceBeforeChanges = Distance;
+
+	if(Rotating){
+		m_bFixingBeta = true;
+
+		while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI;
+		while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI;
+
+		while(Beta >= PI) Beta -= 2*PI;
+		while(Beta < -PI) Beta += 2*PI;
+
+
+/*
+		// This is inlined WellBufferMe
+		DeltaBeta = FixedTargetOrientation - Beta;
+		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+
+		float ReqSpeed = DeltaBeta * MaxSpeed;
+		// Add or subtract absolute depending on sign, genius!
+		if(ReqSpeed - BetaSpeed > 0.0f)
+			BetaSpeed += SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
+		else
+			BetaSpeed -= SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
+		// this would be simpler:
+		// BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep;
+
+		if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed)
+			BetaSpeed = ReqSpeed;
+		else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed)
+			BetaSpeed = ReqSpeed;
+
+		Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep());
+*/
+		WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true);
+
+		if(ResetStatics){
+			Beta = FixedTargetOrientation;
+			BetaSpeed = 0.0f;
+		}
+
+		Source.x = TargetCoors.x + Distance * Cos(Beta);
+		Source.y = TargetCoors.y + Distance * Sin(Beta);
+
+		// Check if we can stop rotating
+		DeltaBeta = FixedTargetOrientation - Beta;
+		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+		if(Abs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){
+			// Stop rotation
+			PickedASide = false;
+			Rotating = false;
+			BetaSpeed = 0.0f;
+		}
+	}
+
+
+	if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront ||
+	   HackPlayerOnStoppingTrain || Rotating){
+		if(TheCamera.m_bCamDirectlyBehind){
+			Beta = TargetOrientation + PI;
+			Source.x = TargetCoors.x + Distance * Cos(Beta);
+			Source.y = TargetCoors.y + Distance * Sin(Beta);
+		}
+		if(TheCamera.m_bCamDirectlyInFront){
+			Beta = TargetOrientation;
+			Source.x = TargetCoors.x + Distance * Cos(Beta);
+			Source.y = TargetCoors.y + Distance * Sin(Beta);
+		}
+		if(HackPlayerOnStoppingTrain){
+			Beta = TargetOrientation + PI;
+			Source.x = TargetCoors.x + Distance * Cos(Beta);
+			Source.y = TargetCoors.y + Distance * Sin(Beta);
+			m_fDimensionOfHighestNearCar = 0.0f;
+			m_fCamBufferedHeight = 0.0f;
+			m_fCamBufferedHeightSpeed = 0.0f;
+		}
+		// Beta and Source already set in the rotation code
+	}else{
+		Source = IdealSource;
+		BetaSpeed = 0.0f;
+	}
+
+	// Subtract m_fRoadOffSet from both?
+	TargetCoors.z -= m_fRoadOffSet;
+	Source.z = IdealSource.z - m_fRoadOffSet;
+
+	// Apply zoom now
+	// m_fPedZoomValueSmooth makes the cam go down the further out it is
+	//  0.25 ->  0.20 for nearest dist
+	//  1.50 -> -0.05 for mid dist
+	//  2.90 -> -0.33 for far dist
+	Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f;
+	// Zoom out camera
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	Source -= Front * TheCamera.m_fPedZoomValueSmooth;
+	// and then we move up again
+	//  -0.375
+	//   0.25
+	//   0.95
+	Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset;
+
+
+	// Process height offset to avoid peds and cars
+
+	float TargetZOffSet = m_fRoadOffSet + m_fDimensionOfHighestNearCar;
+	TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset);
+	float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z;
+
+	if(TargetHeight > m_fCamBufferedHeight){
+		// Have to go up
+		if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight)
+			WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false);
+		else if(TargetZOffSet == m_fRoadOffSet && TargetZOffSet > m_fCamBufferedHeight){
+			// TODO: figure this out
+			bool foo = false;
+			switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched)
+			case SURFACE_GRASS:
+			case SURFACE_DIRT:
+			case SURFACE_PAVEMENT:
+			case SURFACE_STEEL:
+			case SURFACE_TIRE:
+			case SURFACE_STONE:
+				foo = true;
+			if(foo)
+				WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false);
+			else
+				WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
+		}else
+			WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
+		StartedCountingForGoDown = false;
+	}else{
+		// Have to go down
+		if(StartedCountingForGoDown){
+			if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){
+				if(TargetHeight > 0.0f)
+					WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
+				else
+					WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
+			}
+		}else{
+			StartedCountingForGoDown = true;
+			TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds();
+		}
+	}
+
+	Source.z += m_fCamBufferedHeight;
+
+
+	// Clip Source if necessary
+
+	bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f;
+	if(GoingBehind || ResetStatics || ClipSource){
+		CColPoint colpoint;
+		CEntity *entity;
+		if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){
+			Source = colpoint.point;
+			if((TargetCoors - Source).Magnitude2D() < 1.0f)
+				RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+		}
+	}
+
+	TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f);
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+
+	Front = TargetCoors - Source;
+	m_fRealGroundDist = Front.Magnitude2D();
+	m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist;	
+	Front.Normalise();
+	GetVectorsReadyForRW();
+	TheCamera.m_bCamDirectlyBehind = false;
+	TheCamera.m_bCamDirectlyInFront = false;
+	PreviouslyObscured = BuildingCheckObscured;
+
+	ResetStatics = false;
+}
+
+static float fBaseDist = 1.7f;
+static float fAngleDist = 2.0f;
+static float fFalloff = 3.0f;
+static float fStickSens = 0.01f;
+static float fTweakFOV = 1.05f;
+static float fTranslateCamUp = 0.8f;
+static int16 nFadeControlThreshhold = 45;
+static float fDefaultAlphaOrient = -0.22f;
+
+void
+CCam::Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	FOV = DefaultFOV;
+
+	if(!CamTargetEntity->IsPed())
+		return;
+
+	CVector TargetCoors;
+	float CamDist;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	if(ResetStatics){
+		Rotating = false;
+		m_bCollisionChecksOn = true;
+		CPad::GetPad(0)->ClearMouseHistory();
+		ResetStatics = false;
+	}
+
+	bool OnTrain = FindPlayerVehicle() && FindPlayerVehicle()->IsTrain();
+
+	// Look around
+	bool UseMouse = false;
+	float MouseX = CPad::GetPad(0)->GetMouseX();
+	float MouseY = CPad::GetPad(0)->GetMouseY();
+	float LookLeftRight, LookUpDown;
+	if((MouseX != 0.0f || MouseY != 0.0f) && !CPad::GetPad(0)->ArePlayerControlsDisabled()){
+		UseMouse = true;
+		LookLeftRight = -2.5f*MouseX;
+		LookUpDown = 4.0f*MouseY;
+	}else{
+		LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight();
+		LookUpDown = CPad::GetPad(0)->LookAroundUpDown();
+	}
+	float AlphaOffset, BetaOffset;
+	if(UseMouse){
+		BetaOffset = LookLeftRight * TheCamera.m_fMouseAccelHorzntl * FOV/80.0f;
+		AlphaOffset = LookUpDown * TheCamera.m_fMouseAccelVertical * FOV/80.0f;
+	}else{
+		BetaOffset = LookLeftRight * fStickSens * (0.5f/7.0f) * FOV/80.0f * CTimer::GetTimeStep();
+		AlphaOffset = LookUpDown * fStickSens * (0.3f/7.0f) * FOV/80.0f * CTimer::GetTimeStep();
+	}
+
+	if(TheCamera.GetFading() && TheCamera.GetFadingDirection() == FADE_IN && nFadeControlThreshhold < CDraw::FadeValue ||
+	   CDraw::FadeValue > 200){
+		if(Alpha < fDefaultAlphaOrient-0.05f)
+			AlphaOffset = 0.05f;
+		else if(Alpha < fDefaultAlphaOrient)
+			AlphaOffset = fDefaultAlphaOrient - Alpha;
+		else if(Alpha > fDefaultAlphaOrient+0.05f)
+			AlphaOffset = -0.05f;
+		else if(Alpha > fDefaultAlphaOrient)
+			AlphaOffset = fDefaultAlphaOrient - Alpha;
+		else
+			AlphaOffset = 0.0f;
+	}
+
+	Alpha += AlphaOffset;
+	Beta += BetaOffset;
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+	if(Alpha > DEGTORAD(45.0f)) Alpha = DEGTORAD(45.0f);
+	if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+	TargetCoors = CameraTarget;
+	TargetCoors.z += fTranslateCamUp;
+	TargetCoors = DoAverageOnVector(TargetCoors);
+
+	if(Alpha > fBaseDist)	// comparing an angle against a distance?
+		CamDist = fBaseDist + Cos(min(Alpha*fFalloff, HALFPI))*fAngleDist;
+	else
+		CamDist = fBaseDist + Cos(Alpha)*fAngleDist;
+
+	if(TheCamera.m_bUseTransitionBeta)
+		Beta = -CGeneral::GetATanOfXY(-Cos(m_fTransitionBeta), -Sin(m_fTransitionBeta));
+
+	if(TheCamera.m_bCamDirectlyBehind)
+		Beta = TheCamera.m_PedOrientForBehindOrInFront;
+	if(TheCamera.m_bCamDirectlyInFront)
+		Beta = TheCamera.m_PedOrientForBehindOrInFront + PI;
+	if(OnTrain)
+		Beta = TargetOrientation;
+
+	Front.x = Cos(Alpha) * Cos(Beta);
+	Front.y = Cos(Alpha) * Sin(Beta);
+	Front.z = Sin(Alpha);
+	Source = TargetCoors - Front*CamDist;
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+
+	// Clip Source and fix near clip
+	CWorld::pIgnoreEntity = CamTargetEntity;
+	entity = nil;
+	if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, true, true, true, false, false, true)){
+		float PedColDist = (TargetCoors - colPoint.point).Magnitude();
+		float ColCamDist = CamDist - PedColDist;
+		if(entity->IsPed() && ColCamDist > 1.0f){
+			// Ped in the way but not clipping through
+			if(CWorld::ProcessLineOfSight(colPoint.point, Source, colPoint, entity, true, true, true, true, false, false, true)){
+				PedColDist = (TargetCoors - colPoint.point).Magnitude();
+				Source = colPoint.point;
+				if(PedColDist < 0.9f + 0.3f)
+					RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f));
+			}else{
+				RwCameraSetNearClipPlane(Scene.camera, min(ColCamDist-0.35f, 0.9f));
+			}
+		}else{
+			Source = colPoint.point;
+			if(PedColDist < 0.9f + 0.3f)
+				RwCameraSetNearClipPlane(Scene.camera, max(PedColDist-0.3f, 0.05f));
+		}
+	}
+	CWorld::pIgnoreEntity = nil;
+
+	float ViewPlaneHeight = Tan(DEGTORAD(FOV) / 2.0f);
+	float ViewPlaneWidth = ViewPlaneHeight * CDraw::FindAspectRatio() * fTweakFOV;
+	float Near = RwCameraGetNearClipPlane(Scene.camera);
+	float radius = ViewPlaneWidth*Near;
+	entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false);
+	int i = 0;
+	while(entity){
+		CVector CamToCol = gaTempSphereColPoints[0].point - Source;
+		float frontDist = DotProduct(CamToCol, Front);
+		float dist = (CamToCol - Front*frontDist).Magnitude() / ViewPlaneWidth;
+
+		// Try to decrease near clip
+		dist = max(min(Near, dist), 0.1f);
+		if(dist < Near)
+			RwCameraSetNearClipPlane(Scene.camera, dist);
+
+		// Move forward a bit
+		if(dist == 0.1f)
+			Source += (TargetCoors - Source)*0.3f;
+
+#ifndef FIX_BUGS
+		// this is totally wrong...
+		radius = Tan(FOV / 2.0f) * Near;
+#endif
+		// Keep testing
+		entity = CWorld::TestSphereAgainstWorld(Source + Front*Near, radius, nil, true, true, false, true, false, false);
+
+		i++;
+		if(i > 5)
+			entity = nil;
+	}
+
+	if(CamTargetEntity->m_rwObject){
+		// what's going on here?
+		if(RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_PUMP) ||
+		   RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_THROW) ||
+		   RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_THROWU) ||
+		   RpAnimBlendClumpGetAssociation(CamTargetEntity->GetClump(), ANIM_WEAPON_START_THROW)){
+			CPed *player = FindPlayerPed();
+			float PlayerDist = (Source - player->GetPosition()).Magnitude();
+			if(PlayerDist < 2.75f)
+				Near = PlayerDist/2.75f * 0.9f - 0.3f;
+			RwCameraSetNearClipPlane(Scene.camera, max(Near, 0.1f));
+		}
+	}
+
+	TheCamera.m_bCamDirectlyInFront = false;
+	TheCamera.m_bCamDirectlyBehind = false;
+
+	GetVectorsReadyForRW();
+
+	if(((CPed*)CamTargetEntity)->CanStrafeOrMouseControl() && CDraw::FadeValue < 250 &&
+	   (TheCamera.GetFadingDirection() != FADE_OUT || CDraw::FadeValue <= 100)){
+		float Heading = Front.Heading();
+		((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading;
+		((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading;
+		TheCamera.pTargetEntity->SetHeading(Heading);
+		TheCamera.pTargetEntity->GetMatrix().UpdateRW();
+	}
+}
+
+void
+CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	FOV = DefaultFOV;
+
+	if(!CamTargetEntity->IsVehicle())
+		return;
+
+	CVector TargetCoors = CameraTarget;
+	TargetCoors.z -= 0.2f;
+	CA_MAX_DISTANCE = 9.95f;
+	CA_MIN_DISTANCE = 8.5f;
+
+	CVector Dist = Source - TargetCoors;
+	float Length = Dist.Magnitude2D();
+	m_fDistanceBeforeChanges = Length;
+	if(Length < 0.002f)
+		Length = 0.002f;
+	Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
+	if(Length > CA_MAX_DISTANCE){
+		Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
+		Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
+	}else if(Length < CA_MIN_DISTANCE){
+		Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
+		Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
+	}
+	TargetCoors.z += 0.8f;
+
+	WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation);
+	RotCamIfInFrontCar(TargetCoors, TargetOrientation);
+	FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation);
+
+	Front = TargetCoors - Source;
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+	ResetStatics = false;
+	GetVectorsReadyForRW();
+}
+
+void
+CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation)
+{
+	CColPoint colpoint;
+	CEntity *ent;
+	float TargetZOffSet = 0.0f;
+	static bool PreviouslyFailedRoadHeightCheck = false;
+	static float RoadHeightFix = 0.0f;
+	static float RoadHeightFixSpeed = 0.0f;
+
+	if(ResetStatics){
+		RoadHeightFix = 0.0f;
+		RoadHeightFixSpeed = 0.0f;
+		Alpha = DEGTORAD(25.0f);
+		AlphaSpeed = 0.0f;
+	}
+	float AlphaTarget = DEGTORAD(25.0f);
+	if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
+		AlphaTarget = DEGTORAD(14.0f);
+	WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true);
+	Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha);
+
+	if(FindPlayerVehicle()){
+		m_fRoadOffSet = 0.0f;
+		bool FoundRoad = false;
+		bool FoundRoof = false;
+		float RoadZ = 0.0f;
+		float RoofZ = 0.0f;
+
+		if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
+		   ent->IsBuilding()){
+			FoundRoad = true;
+			RoadZ = colpoint.point.z;
+		}
+
+		if(FoundRoad){
+			if(Source.z - RoadZ < 0.9f){
+				PreviouslyFailedRoadHeightCheck = true;
+				TargetZOffSet = RoadZ + 0.9f - Source.z;
+			}else{
+				if(m_bCollisionChecksOn)
+					PreviouslyFailedRoadHeightCheck = false;
+				else
+					TargetZOffSet = 0.0f;
+			}
+		}else{
+			if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
+			   ent->IsBuilding()){
+				FoundRoof = true;
+				RoofZ = colpoint.point.z;
+			}
+			if(FoundRoof){
+				if(Source.z - RoofZ < 0.9f){
+					PreviouslyFailedRoadHeightCheck = true;
+					TargetZOffSet = RoofZ + 0.9f - Source.z;
+				}else{
+					if(m_bCollisionChecksOn)
+						PreviouslyFailedRoadHeightCheck = false;
+					else
+						TargetZOffSet = 0.0f;
+				}
+			}
+		}
+	}
+
+	if(TargetZOffSet > RoadHeightFix)
+		RoadHeightFix = TargetZOffSet;
+	else
+		WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false);
+
+	if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) &&
+	   colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE &&
+	   RoadHeightFix > 1.4f)
+		RoadHeightFix = 1.4f;
+
+	Source.z += RoadHeightFix;
+}
+
+void
+CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight)
+{
+	static float LastTargetAlphaWithCollisionOn = 0.0f;
+	static float LastTopAlphaSpeed = 0.0f;
+	static float LastAlphaSpeedStep = 0.0f;
+	static bool PreviousNearCheckNearClipSmall = false;
+
+	bool CamClear = true;
+	float ModeAlpha = 0.0f;
+
+	if(ResetStatics){
+		LastTargetAlphaWithCollisionOn = 0.0f;
+		LastTopAlphaSpeed = 0.0f;
+		LastAlphaSpeedStep = 0.0f;
+		PreviousNearCheckNearClipSmall = false;
+	}
+
+	float TopAlphaSpeed = 0.15f;
+	float AlphaSpeedStep = 0.015f;
+
+	float zoomvalue = TheCamera.CarZoomValueSmooth;
+	if(zoomvalue < 0.1f)
+		zoomvalue = 0.1f;
+	if(TheCamera.CarZoomIndicator == 1.0f)
+		ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue);	// near
+	else if(TheCamera.CarZoomIndicator == 2.0f)
+		ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue);	// mid
+	else if(TheCamera.CarZoomIndicator == 3.0f)
+		ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue);	// far
+
+
+	float Length = (Source - TargetCoors).Magnitude2D();
+	if(m_bCollisionChecksOn){	// there's another variable (on PC) but it's uninitialised
+		CVector Forward = CamTargetEntity->GetForward();
+		float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z);
+		// this shouldn't be necessary....
+		while(CarAlpha >= PI) CarAlpha -= 2*PI;
+		while(CarAlpha < -PI) CarAlpha += 2*PI;
+
+		while(Beta >= PI) Beta -= 2*PI;
+		while(Beta < -PI) Beta += 2*PI;
+
+		float deltaBeta = Beta - TargetOrientation;
+		while(deltaBeta >= PI) deltaBeta -= 2*PI;
+		while(deltaBeta < -PI) deltaBeta += 2*PI;
+
+		float BehindCarNess = Cos(deltaBeta);	// 1 if behind car, 0 if side, -1 if in front
+		CarAlpha = -CarAlpha * BehindCarNess;
+		if(CarAlpha < -0.01f)
+			CarAlpha = -0.01f;
+
+		float DeltaAlpha = CarAlpha - Alpha;
+		while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
+		while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
+		// What's this?? wouldn't it make more sense to clamp?
+		float AngleLimit = DEGTORAD(1.8f);
+		if(DeltaAlpha < -AngleLimit)
+			DeltaAlpha += AngleLimit;
+		else if(DeltaAlpha > AngleLimit)
+			DeltaAlpha -= AngleLimit;
+		else
+			DeltaAlpha = 0.0f;
+
+		// Now the collision
+
+		float TargetAlpha = 0.0f;
+		bool FoundRoofCenter = false;
+		bool FoundRoofSide1 = false;
+		bool FoundRoofSide2 = false;
+		bool FoundCamRoof = false;
+		bool FoundCamGround = false;
+		float CamRoof = 0.0f;
+		float CarBottom = TargetCoors.z - TargetHeight/2.0f;
+
+		// Check car center
+		float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter);
+
+		// Check sides of the car
+		Forward = CamTargetEntity->GetForward();	// we actually still have that...
+		Forward.Normalise();	// shouldn't be necessary
+		float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f;
+		float SideX = 2.5f * Cos(CarSideAngle);
+		float SideY = 2.5f * Sin(CarSideAngle);
+		CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1);
+		CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2);
+
+		// Now find out at what height we'd like to place the camera
+		float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*Sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround);
+		float CamTargetZ = 0.0f;
+		if(FoundCamGround){
+			// This is the normal case
+			CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof);
+			CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f;
+		}else{
+			FoundCamRoof = false;
+			CamTargetZ = TargetCoors.z;
+		}
+
+		if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){
+			// Car is under something but camera isn't
+			// This seems weird...
+			TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f);
+			CamClear = false;
+		}
+		if(FoundCamRoof){
+			// Camera is under something
+			float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof;
+			// Same weirdness again?
+			TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f);
+			CamClear = false;
+		}
+		while(TargetAlpha >= PI) TargetAlpha -= 2*PI;
+		while(TargetAlpha < -PI) TargetAlpha += 2*PI;
+		if(TargetAlpha < DEGTORAD(-7.0f))
+			TargetAlpha = DEGTORAD(-7.0f);
+
+		// huh?
+		if(TargetAlpha > ModeAlpha)
+			CamClear = true;
+		// Camera is contrained by collision in some way
+		PreviousNearCheckNearClipSmall = false;
+		if(!CamClear){
+			PreviousNearCheckNearClipSmall = true;
+			RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+
+			DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha);
+			while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
+			while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
+
+			TopAlphaSpeed = 0.3f;
+			AlphaSpeedStep = 0.03f;
+		}
+
+		// Now do things if CamClear...but what is that anyway?
+		float CamZ = TargetCoors.z + Length*Sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset;
+		bool FoundGround, FoundRoof;
+		float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround);
+		if(FoundGround){
+			if(CamClear)
+				if(CamZ - CamGround2 < 1.5f){
+					PreviousNearCheckNearClipSmall = true;
+					RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+
+					float a;
+					if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f)
+						a = Alpha;
+					else
+						a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z);
+					while(a > PI) a -= 2*PI;
+					while(a < -PI) a += 2*PI;
+					DeltaAlpha = a - Alpha;
+				}
+		}else{
+			if(CamClear){
+				float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof);
+				if(FoundRoof && CamZ - CamRoof2 < 1.5f){
+					PreviousNearCheckNearClipSmall = true;
+					RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+
+					if(CamRoof2 > TargetCoors.z + 3.5f)
+						CamRoof2 = TargetCoors.z + 3.5f;
+
+					float a;
+					if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f)
+						a = Alpha;
+					else
+						a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z);
+					while(a > PI) a -= 2*PI;
+					while(a < -PI) a += 2*PI;
+					DeltaAlpha = a - Alpha;
+				}
+			}
+		}
+
+		LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha;
+		LastTopAlphaSpeed = TopAlphaSpeed;
+		LastAlphaSpeedStep = AlphaSpeedStep;
+	}else{
+		if(PreviousNearCheckNearClipSmall)
+			RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+	}
+
+	WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true);
+
+	Source.z = TargetCoors.z + Sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset;
+}
+
+// Rotate cam behind the car when the car is moving forward
+bool
+CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation)
+{
+	bool MovingForward = false;
+	CPhysical *phys = (CPhysical*)CamTargetEntity;
+
+	float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f)));
+	if(ForwardSpeed > 0.02f)
+		MovingForward = true;
+
+	float Dist = (Source - TargetCoors).Magnitude2D();
+
+	float DeltaBeta = TargetOrientation - Beta;
+	while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+	while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+
+	if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0)
+		m_bFixingBeta = true;
+
+	CPad *pad = CPad::GetPad(0);
+	if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()))
+		if(DirectionWasLooking != LOOKING_FORWARD)
+			TheCamera.m_bCamDirectlyBehind = true;
+
+	if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront)
+		return false;
+
+	bool SetBeta = false;
+	if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta)
+		if(&TheCamera.Cams[TheCamera.ActiveCam] == this)
+			SetBeta = true;
+
+	if(m_bFixingBeta || SetBeta){
+		WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true);
+
+		if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this)
+			Beta = TargetOrientation;
+		if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this)
+			Beta = TargetOrientation + PI;
+		if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this)
+			Beta = m_fTransitionBeta;
+
+		Source.x = TargetCoors.x - Cos(Beta)*Dist;
+		Source.y = TargetCoors.y - Sin(Beta)*Dist;
+
+		// Check if we're done
+		DeltaBeta = TargetOrientation - Beta;
+		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+		if(Abs(DeltaBeta) < DEGTORAD(2.0f))
+			m_bFixingBeta = false;
+	}
+	TheCamera.m_bCamDirectlyBehind = false;
+	TheCamera.m_bCamDirectlyInFront = false;
+	return true;
+}
+
+// Move the cam to avoid clipping through buildings
+bool
+CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation)
+{
+	CVector Target = TargetCoors;
+	bool UseEntityPos = false;
+	CVector EntityPos;
+	static CColPoint colPoint;
+	static bool LastObscured = false;
+
+	if(Mode == MODE_BEHINDCAR)
+		Target.z += TargetHeight/2.0f;
+	if(Mode == MODE_CAM_ON_A_STRING){
+		UseEntityPos = true;
+		Target.z += TargetHeight/2.0f;
+		EntityPos = CamTargetEntity->GetPosition();
+	}
+
+	CVector TempSource = Source;
+
+	bool Obscured1 = false;
+	bool Obscured2 = false;
+	bool Fix1 = false;
+	float Dist1 = 0.0f;
+	float Dist2 = 0.0f;
+	CEntity *ent;
+	if(m_bCollisionChecksOn || LastObscured){
+		Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+		if(Obscured1){
+			Dist1 = (Target - colPoint.point).Magnitude2D();
+			Fix1 = true;
+			if(UseEntityPos)
+				Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+		}else if(m_bFixingBeta){
+			float d = (TempSource - Target).Magnitude();
+			TempSource.x = Target.x - d*Cos(TargetOrientation);
+			TempSource.y = Target.y - d*Sin(TargetOrientation);
+
+			// same check again
+			Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+			if(Obscured2){
+				Dist2 = (Target - colPoint.point).Magnitude2D();
+				if(UseEntityPos)
+					Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
+			}
+		}
+		LastObscured = Obscured1 || Obscured2;
+	}
+
+	// nothing to do
+	if(!LastObscured)
+		return false;
+
+	if(Fix1){
+		Source.x = Target.x - Cos(Beta)*Dist1;
+		Source.y = Target.y - Sin(Beta)*Dist1;
+		if(Mode == MODE_BEHINDCAR)
+			Source = colPoint.point;
+	}else{
+		WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false);
+		Source.x = Target.x - Cos(Beta)*m_fDistanceBeforeChanges;
+		Source.y = Target.y - Sin(Beta)*m_fDistanceBeforeChanges;
+	}
+
+	if(ResetStatics){
+		m_fDistanceBeforeChanges = (Source - Target).Magnitude2D();
+		DistanceSpeed = 0.0f;
+		Source.x = colPoint.point.x;
+		Source.y = colPoint.point.y;
+	}
+	return true;
+}
+
+void
+CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	if(!CamTargetEntity->IsVehicle())
+		return;
+
+	FOV = DefaultFOV;
+
+	if(ResetStatics){
+		AlphaSpeed = 0.0f;
+		if(TheCamera.m_bIdleOn)
+			TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds();
+	}
+
+	CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex());
+	CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min;
+	float BaseDist = Dimensions.Magnitude2D();
+
+	CVector TargetCoors = CameraTarget;
+	TargetCoors.z += Dimensions.z - 0.1f;	// final
+	Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
+	while(Alpha >= PI) Alpha -= 2*PI;
+	while(Alpha < -PI) Alpha += 2*PI;
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+
+	m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D();
+
+	Cam_On_A_String_Unobscured(TargetCoors, BaseDist);
+	WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z);
+	RotCamIfInFrontCar(TargetCoors, TargetOrientation);
+	FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation);
+	FixCamWhenObscuredByVehicle(TargetCoors);
+
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	GetVectorsReadyForRW();
+	ResetStatics = false;
+}
+
+// Basic Cam on a string algorithm
+void
+CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist)
+{
+	CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth;
+	CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f);
+
+	CVector Dist = Source - TargetCoors;
+
+	if(ResetStatics)
+		Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f);
+
+	float Length = Dist.Magnitude2D();
+	if(Length < 0.001f){
+		// This probably shouldn't happen. reset view
+		CVector Forward = CamTargetEntity->GetForward();
+		Forward.z = 0.0f;
+		Forward.Normalise();
+		Source = TargetCoors - Forward*CA_MAX_DISTANCE;
+		Dist = Source - TargetCoors;
+		Length = Dist.Magnitude2D();
+	}
+
+	if(Length > CA_MAX_DISTANCE){
+		Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
+		Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
+	}else if(Length < CA_MIN_DISTANCE){
+		Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
+		Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
+	}
+}
+
+void
+CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors)
+{
+	// BUG? is this never reset
+	static float HeightFixerCarsObscuring = 0.0f;
+	static float HeightFixerCarsObscuringSpeed = 0.0f;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	float HeightTarget = 0.0f;
+	if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){
+		CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex());
+		HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z;
+		if(HeightTarget < 0.0f)
+			HeightTarget = 0.0f;
+	}
+	WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false);
+	Source.z += HeightFixerCarsObscuring;
+}
+
+void
+CCam::Process_TopDown(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar)
+{
+	FOV = DefaultFOV;
+
+	if(!CamTargetEntity->IsVehicle())
+		return;
+
+	float Dist;
+	float HeightTarget = 0.0f;
+	static float AdjustHeightTargetMoveBuffer = 0.0f;
+	static float AdjustHeightTargetMoveSpeed = 0.0f;
+	static float NearClipDistance = 1.5f;
+	const float FarClipDistance = 200.0f;
+	CVector TargetFront, Target;
+	CVector TestSource, TestTarget;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	TargetFront = CameraTarget;
+	TargetFront.x += 18.0f*CamTargetEntity->GetForward().x*SpeedVar;
+	TargetFront.y += 18.0f*CamTargetEntity->GetForward().y*SpeedVar;
+
+	if(ResetStatics){
+		AdjustHeightTargetMoveBuffer = 0.0f;
+		AdjustHeightTargetMoveSpeed = 0.0f;
+	}
+
+	float f = Pow(0.8f, 4.0f);
+	Target = f*CameraTarget + (1.0f-f)*TargetFront;
+	if(Mode == MODE_GTACLASSIC)
+		SpeedVar = TargetSpeedVar;
+	Source = Target + CVector(0.0f, 0.0f, (40.0f*SpeedVar + 30.0f)*0.8f);
+	// What is this? looks horrible
+	if(Mode == MODE_GTACLASSIC)
+		Source.x += (uint8)(100.0f*CameraTarget.x)/500.0f;
+
+	TestSource = Source;
+	TestTarget = TestSource;
+	TestTarget.z = Target.z;
+	if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){
+		if(Source.z < colPoint.point.z+3.0f)
+			HeightTarget = colPoint.point.z+3.0f - Source.z;
+	}else{
+		TestSource = Source;
+		TestTarget = TestSource;
+		TestTarget.z += 10.0f;
+		if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false))
+			if(Source.z < colPoint.point.z+3.0f)
+				HeightTarget = colPoint.point.z+3.0f - Source.z;
+	}
+	WellBufferMe(HeightTarget, &AdjustHeightTargetMoveBuffer, &AdjustHeightTargetMoveSpeed, 0.2f, 0.02f, false);
+	Source.z += AdjustHeightTargetMoveBuffer;
+
+	if(RwCameraGetFarClipPlane(Scene.camera) > FarClipDistance)
+		RwCameraSetFarClipPlane(Scene.camera, FarClipDistance);
+	RwCameraSetNearClipPlane(Scene.camera, NearClipDistance);
+
+	Front = CVector(-0.01f, -0.01f, -1.0f);	// look down
+	Front.Normalise();
+	Dist = (Source - CameraTarget).Magnitude();
+	m_cvecTargetCoorsForFudgeInter = Dist*Front + Source;
+	Up = CVector(0.0f, 1.0f, 0.0f);
+
+	ResetStatics = false;
+}
+
+void
+CCam::AvoidWallsTopDownPed(const CVector &TargetCoors, const CVector &Offset, float *Adjuster, float *AdjusterSpeed, float yDistLimit)
+{
+	float Target = 0.0f;
+	float MaxSpeed = 0.13f;
+	float Acceleration = 0.015f;
+	float SpeedMult;
+	float dy;
+	CVector TestPoint2;
+	CVector TestPoint1;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	TestPoint2 = TargetCoors + Offset;
+	TestPoint1 = TargetCoors;
+	TestPoint1.z = TestPoint2.z;
+	if(CWorld::ProcessLineOfSight(TestPoint1, TestPoint2, colPoint, entity, true, false, false, false, false, false, false)){
+		// What is this even?
+		dy = TestPoint1.y - colPoint.point.y;
+		if(dy > yDistLimit)
+			dy = yDistLimit;
+		SpeedMult = yDistLimit - Abs(dy/yDistLimit);
+
+		Target = 2.5f;
+		MaxSpeed += SpeedMult*0.3f;
+		Acceleration += SpeedMult*0.03f;
+	}
+	WellBufferMe(Target, Adjuster, AdjusterSpeed, MaxSpeed, Acceleration, false);
+}
+
+void
+CCam::Process_TopDownPed(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	if(!CamTargetEntity->IsPed())
+		return;
+
+	float Dist;
+	float HeightTarget;
+	static int NumPedPosCountsSoFar = 0;
+	static float PedAverageSpeed = 0.0f;
+	static float AdjustHeightTargetMoveBuffer = 0.0f;
+	static float AdjustHeightTargetMoveSpeed = 0.0f;
+	static float PedSpeedSoFar = 0.0f;
+	static float FarClipDistance = 200.0f;
+	static float NearClipDistance = 1.5f;
+	static float TargetAdjusterForSouth = 0.0f;
+	static float TargetAdjusterSpeedForSouth = 0.0f;
+	static float TargetAdjusterForNorth = 0.0f;
+	static float TargetAdjusterSpeedForNorth = 0.0f;
+	static float TargetAdjusterForEast = 0.0f;
+	static float TargetAdjusterSpeedForEast = 0.0f;
+	static float TargetAdjusterForWest = 0.0f;
+	static float TargetAdjusterSpeedForWest = 0.0f;
+	static CVector PreviousPlayerMoveSpeedVec;
+	CVector TargetCoors, PlayerMoveSpeed;
+	CVector TestSource, TestTarget;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	FOV = DefaultFOV;
+	TargetCoors = CameraTarget;
+	PlayerMoveSpeed = ((CPed*)CamTargetEntity)->GetMoveSpeed();
+
+	if(ResetStatics){
+		PreviousPlayerMoveSpeedVec = PlayerMoveSpeed;
+		AdjustHeightTargetMoveBuffer = 0.0f;
+		AdjustHeightTargetMoveSpeed = 0.0f;
+		NumPedPosCountsSoFar = 0;
+		PedSpeedSoFar = 0.0f;
+		PedAverageSpeed = 0.0f;
+		TargetAdjusterForWest = 0.0f;
+		TargetAdjusterSpeedForWest = 0.0f;
+		TargetAdjusterForEast = 0.0f;
+		TargetAdjusterSpeedForEast = 0.0f;
+		TargetAdjusterForNorth = 0.0f;
+		TargetAdjusterSpeedForNorth = 0.0f;
+		TargetAdjusterForSouth = 0.0f;
+		TargetAdjusterSpeedForSouth = 0.0f;
+	}
+
+	if(RwCameraGetFarClipPlane(Scene.camera) > FarClipDistance)
+		RwCameraSetFarClipPlane(Scene.camera, FarClipDistance);
+	RwCameraSetNearClipPlane(Scene.camera, NearClipDistance);
+
+	// Average ped speed
+	NumPedPosCountsSoFar++;
+	PedSpeedSoFar += PlayerMoveSpeed.Magnitude();
+	if(NumPedPosCountsSoFar == 5){
+		PedAverageSpeed = 0.4f*PedAverageSpeed + 0.6*(PedSpeedSoFar/5.0f);
+		NumPedPosCountsSoFar = 0;
+		PedSpeedSoFar = 0.0f;
+	}
+	PreviousPlayerMoveSpeedVec = PlayerMoveSpeed;
+
+	// Zoom out depending on speed
+	if(PedAverageSpeed > 0.01f && PedAverageSpeed <= 0.04f)
+		HeightTarget = 2.5f;
+	else if(PedAverageSpeed > 0.04f && PedAverageSpeed <= 0.145f)
+		HeightTarget = 4.5f;
+	else if(PedAverageSpeed > 0.145f)
+		HeightTarget = 7.0f;
+	else
+		HeightTarget = 0.0f;
+
+	// Zoom out if locked on target is far away
+	if(FindPlayerPed()->m_pPointGunAt){
+		Dist = (FindPlayerPed()->m_pPointGunAt->GetPosition() - CameraTarget).Magnitude2D();
+		if(Dist > 6.0f)
+			HeightTarget = max(HeightTarget, Dist/22.0f*37.0f);
+	}
+
+	Source = TargetCoors + CVector(0.0f, -1.0f, 9.0f);
+
+	// Collision checks
+	entity = nil;
+	TestSource = TargetCoors + CVector(0.0f, -1.0f, 9.0f);
+	TestTarget = TestSource;
+	TestTarget.z = TargetCoors.z;
+	if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){
+		if(TargetCoors.z+9.0f+HeightTarget < colPoint.point.z+3.0f)
+			HeightTarget = colPoint.point.z+3.0f - (TargetCoors.z+9.0f);
+	}else{
+		TestSource = TargetCoors + CVector(0.0f, -1.0f, 9.0f);
+		TestTarget = TestSource;
+		TestSource.z += HeightTarget;
+		TestTarget.z = TestSource.z + 10.0f;
+		if(CWorld::ProcessLineOfSight(TestTarget, TestSource, colPoint, entity, true, false, false, false, false, false, false)){
+			if(TargetCoors.z+9.0f+HeightTarget < colPoint.point.z+3.0f)
+				HeightTarget = colPoint.point.z+3.0f - (TargetCoors.z+9.0f);
+		}
+	}
+
+	WellBufferMe(HeightTarget, &AdjustHeightTargetMoveBuffer, &AdjustHeightTargetMoveSpeed, 0.3f, 0.03f, false);
+	Source.z += AdjustHeightTargetMoveBuffer;
+
+	// Wall checks
+	AvoidWallsTopDownPed(TargetCoors, CVector(0.0f, -3.0f, 3.0f), &TargetAdjusterForSouth, &TargetAdjusterSpeedForSouth, 1.0f);
+	Source.y += TargetAdjusterForSouth;
+	AvoidWallsTopDownPed(TargetCoors, CVector(0.0f, 3.0f, 3.0f), &TargetAdjusterForNorth, &TargetAdjusterSpeedForNorth, 1.0f);
+	Source.y -= TargetAdjusterForNorth;
+	// BUG: east and west flipped
+	AvoidWallsTopDownPed(TargetCoors, CVector(3.0f, 0.0f, 3.0f), &TargetAdjusterForWest, &TargetAdjusterSpeedForWest, 1.0f);
+	Source.x -= TargetAdjusterForWest;
+	AvoidWallsTopDownPed(TargetCoors, CVector(-3.0f, 0.0f, 3.0f), &TargetAdjusterForEast, &TargetAdjusterSpeedForEast, 1.0f);
+	Source.x += TargetAdjusterForEast;
+
+	TargetCoors.y = Source.y + 1.0f;
+	TargetCoors.y += TargetAdjusterForSouth;
+	TargetCoors.x += TargetAdjusterForEast;
+	TargetCoors.x -= TargetAdjusterForWest;
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+#ifdef FIX_BUGS
+	if(Front.x == 0.0f && Front.y == 0.0f)
+		Front.y = 0.0001f;
+#else
+	// someone used = instead of == in the above check by accident
+	Front.x = 0.0f;
+#endif
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+	Up = CrossProduct(Front, CVector(-1.0f, 0.0f, 0.0f));
+	Up.Normalise();
+
+	ResetStatics = false;
+}
+
+// Identical to M16
+void
+CCam::Process_Rocket(const CVector &CameraTarget, float, float, float)
+{
+	if(!CamTargetEntity->IsPed())
+		return;
+
+	static bool FailedTestTwelveFramesAgo = false;
+	RwV3d HeadPos;
+	CVector TargetCoors;
+
+	FOV = DefaultFOV;
+	TargetCoors = CameraTarget;
+
+	if(ResetStatics){
+		Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+		Alpha = 0.0f;
+		m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+		FailedTestTwelveFramesAgo = false;
+		// static DPadVertical unused
+		// static DPadHorizontal unused
+		m_bCollisionChecksOn = true;
+		ResetStatics = false;
+	}
+
+	((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+	Source = HeadPos;
+	Source.z += 0.1f;
+	Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+	Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+	// Look around
+	bool UseMouse = false;
+	float MouseX = CPad::GetPad(0)->GetMouseX();
+	float MouseY = CPad::GetPad(0)->GetMouseY();
+	float LookLeftRight, LookUpDown;
+	if(MouseX != 0.0f || MouseY != 0.0f){
+		UseMouse = true;
+		LookLeftRight = -3.0f*MouseX;
+		LookUpDown = 4.0f*MouseY;
+	}else{
+		LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight();
+		LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown();
+	}
+	if(UseMouse){
+		Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+		Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+	}else{
+		float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+		float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+		Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+		Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+	}
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+	if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+	if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+	TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+	TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+	TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	Source += Front*0.4f;
+
+	if(m_bCollisionChecksOn){
+		if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+			RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+			FailedTestTwelveFramesAgo = true;
+		}else{
+			CVector TestPoint;
+			TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+			TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+			TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+			if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+				RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+				FailedTestTwelveFramesAgo = true;
+			}else{
+				TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+				TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+				TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+				if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+					RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+					FailedTestTwelveFramesAgo = true;
+				}else
+					FailedTestTwelveFramesAgo = false;
+			}
+		}
+	}
+
+	if(FailedTestTwelveFramesAgo)
+		RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+	Source -= Front*0.4f;
+
+	GetVectorsReadyForRW();
+	float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+	((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+	((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+}
+
+// Identical to Rocket
+void
+CCam::Process_M16_1stPerson(const CVector &CameraTarget, float, float, float)
+{
+	if(!CamTargetEntity->IsPed())
+		return;
+
+	static bool FailedTestTwelveFramesAgo = false;
+	RwV3d HeadPos;
+	CVector TargetCoors;
+
+	FOV = DefaultFOV;
+	TargetCoors = CameraTarget;
+
+	if(ResetStatics){
+		Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+		Alpha = 0.0f;
+		m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+		FailedTestTwelveFramesAgo = false;
+		// static DPadVertical unused
+		// static DPadHorizontal unused
+		m_bCollisionChecksOn = true;
+		ResetStatics = false;
+	}
+
+	((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+	Source = HeadPos;
+	Source.z += 0.1f;
+	Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+	Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+	// Look around
+	bool UseMouse = false;
+	float MouseX = CPad::GetPad(0)->GetMouseX();
+	float MouseY = CPad::GetPad(0)->GetMouseY();
+	float LookLeftRight, LookUpDown;
+	if(MouseX != 0.0f || MouseY != 0.0f){
+		UseMouse = true;
+		LookLeftRight = -3.0f*MouseX;
+		LookUpDown = 4.0f*MouseY;
+	}else{
+		LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight();
+		LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown();
+	}
+	if(UseMouse){
+		Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+		Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+	}else{
+		float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+		float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+		Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+		Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+	}
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+	if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+	if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+	TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+	TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+	TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	Source += Front*0.4f;
+
+	if(m_bCollisionChecksOn){
+		if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+			RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+			FailedTestTwelveFramesAgo = true;
+		}else{
+			CVector TestPoint;
+			TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+			TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+			TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+			if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+				RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+				FailedTestTwelveFramesAgo = true;
+			}else{
+				TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+				TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+				TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+				if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+					RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+					FailedTestTwelveFramesAgo = true;
+				}else
+					FailedTestTwelveFramesAgo = false;
+			}
+		}
+	}
+
+	if(FailedTestTwelveFramesAgo)
+		RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+	Source -= Front*0.4f;
+
+	GetVectorsReadyForRW();
+	float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+	((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+	((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+}
+
+void
+CCam::Process_1stPerson(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	static float DontLookThroughWorldFixer = 0.0f;
+	CVector TargetCoors;
+
+	FOV = DefaultFOV;
+	TargetCoors = CameraTarget;
+	if(CamTargetEntity->m_rwObject == nil)
+		return;
+
+	if(ResetStatics){
+		Beta = TargetOrientation;
+		Alpha = 0.0f;
+		m_fInitialPlayerOrientation = TargetOrientation;
+		if(CamTargetEntity->IsPed()){
+			Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+			Alpha = 0.0f;
+			m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+		}
+		DontLookThroughWorldFixer = 0.0f;
+	}
+
+	if(CamTargetEntity->IsPed()){
+		static bool FailedTestTwelveFramesAgo = false;
+		RwV3d HeadPos;
+
+		TargetCoors = CameraTarget;
+
+		if(ResetStatics){
+			Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+			Alpha = 0.0f;
+			m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+			FailedTestTwelveFramesAgo = false;
+			// static DPadVertical unused
+			// static DPadHorizontal unused
+			m_bCollisionChecksOn = true;
+			ResetStatics = false;
+		}
+
+		((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+		Source = HeadPos;
+		Source.z += 0.1f;
+		Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+		Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+		float LookLeftRight, LookUpDown;
+		LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight();
+		LookUpDown = CPad::GetPad(0)->LookAroundUpDown();
+		float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+		float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+		Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+		Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+		while(Beta >= PI) Beta -= 2*PI;
+		while(Beta < -PI) Beta += 2*PI;
+		if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+		if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+		TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+		TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+		TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+		Front = TargetCoors - Source;
+		Front.Normalise();
+		Source += Front*0.4f;
+
+		if(m_bCollisionChecksOn){
+			if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+				RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+				FailedTestTwelveFramesAgo = true;
+			}else{
+				CVector TestPoint;
+				TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+				TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+				TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+				if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+					RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+					FailedTestTwelveFramesAgo = true;
+				}else{
+					TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+					TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+					TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+					if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+						RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+						FailedTestTwelveFramesAgo = true;
+					}else
+						FailedTestTwelveFramesAgo = false;
+				}
+			}
+		}
+
+		if(FailedTestTwelveFramesAgo)
+			RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+		Source -= Front*0.4f;
+
+		GetVectorsReadyForRW();
+		float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+		((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+		((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+	}else{
+		assert(CamTargetEntity->IsVehicle());
+		CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex());
+		CVector CamPos = mi->m_vehicleType == VEHICLE_TYPE_BOAT ? mi->m_positions[BOAT_POS_FRONTSEAT] : mi->m_positions[CAR_POS_FRONTSEAT];
+		CamPos.x = 0.0f;
+		CamPos.y += -0.08f;
+		CamPos.z += 0.62f;
+		FOV = 60.0f;
+		Source = Multiply3x3(CamTargetEntity->GetMatrix(), CamPos);
+		Source += CamTargetEntity->GetPosition();
+		if(((CVehicle*)CamTargetEntity)->IsBoat())
+			Source.z += 0.5f;
+
+		if(((CVehicle*)CamTargetEntity)->IsUpsideDown()){
+			if(DontLookThroughWorldFixer < 0.5f)
+				DontLookThroughWorldFixer += 0.03f;
+			else
+				DontLookThroughWorldFixer = 0.5f;
+		}else{
+			if(DontLookThroughWorldFixer < 0.0f)
+#ifdef FIX_BUGS
+				DontLookThroughWorldFixer += 0.03f;
+#else
+				DontLookThroughWorldFixer -= 0.03f;
+#endif
+			else
+				DontLookThroughWorldFixer = 0.0f;
+		}
+		Source.z += DontLookThroughWorldFixer;
+		Front = CamTargetEntity->GetForward();
+		Front.Normalise();
+		Up = CamTargetEntity->GetUp();
+		Up.Normalise();
+		CVector Right = CrossProduct(Front, Up);
+		Right.Normalise();
+		Up = CrossProduct(Right, Front);
+		Up.Normalise();
+	}
+
+	ResetStatics = false;
+}
+
+static CVector vecHeadCamOffset(0.06f, 0.05f, 0.0f);
+
+void
+CCam::Process_1rstPersonPedOnPC(const CVector&, float TargetOrientation, float, float)
+{
+	// static int DontLookThroughWorldFixer = 0;	// unused
+	static CVector InitialHeadPos;
+
+	if(Mode != MODE_SNIPER_RUNABOUT)
+		FOV = DefaultFOV;
+	TheCamera.m_1rstPersonRunCloseToAWall = false;
+	if(CamTargetEntity->m_rwObject == nil)
+		return;
+
+	if(CamTargetEntity->IsPed()){
+		// static bool FailedTestTwelveFramesAgo = false;	// unused
+		RwV3d HeadPos = vecHeadCamOffset;
+		CVector TargetCoors;
+
+		// needs fix for SKINNING
+		RwFrame *frm = ((CPed*)CamTargetEntity)->GetNodeFrame(PED_HEAD);
+		while(frm){
+			RwV3dTransformPoints(&HeadPos, &HeadPos, 1, RwFrameGetMatrix(frm));
+			frm = RwFrameGetParent(frm);
+			if(frm == RpClumpGetFrame(CamTargetEntity->GetClump()))
+				frm = nil;
+		}
+
+		if(ResetStatics){
+			Beta = TargetOrientation;
+			Alpha = 0.0f;
+			m_fInitialPlayerOrientation = TargetOrientation;
+			if(CamTargetEntity->IsPed()){	// useless check
+				Beta = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+				Alpha = 0.0f;
+				m_fInitialPlayerOrientation = ((CPed*)CamTargetEntity)->m_fRotationCur + HALFPI;
+				// FailedTestTwelveFramesAgo = false;
+				m_bCollisionChecksOn = true;
+			}
+			// DontLookThroughWorldFixer = false;
+			m_vecBufferedPlayerBodyOffset = HeadPos;
+			InitialHeadPos = HeadPos;
+		}
+
+		m_vecBufferedPlayerBodyOffset.y = HeadPos.y;
+
+		if(TheCamera.m_bHeadBob){
+			m_vecBufferedPlayerBodyOffset.x =
+				TheCamera.m_fGaitSwayBuffer * m_vecBufferedPlayerBodyOffset.x +
+				(1.0f-TheCamera.m_fGaitSwayBuffer) * HeadPos.x;
+			m_vecBufferedPlayerBodyOffset.z =
+				TheCamera.m_fGaitSwayBuffer * m_vecBufferedPlayerBodyOffset.z +
+				(1.0f-TheCamera.m_fGaitSwayBuffer) * HeadPos.z;
+			HeadPos = RwV3d(CamTargetEntity->GetMatrix() * m_vecBufferedPlayerBodyOffset);
+		}else{
+			float HeadDelta = (HeadPos - InitialHeadPos).Magnitude2D();
+			CVector Fwd = CamTargetEntity->GetForward();
+			Fwd.z = 0.0f;
+			Fwd.Normalise();
+			HeadPos = RwV3d(HeadDelta*1.23f*Fwd + CamTargetEntity->GetPosition());
+			HeadPos.z += 0.59f;
+		}
+		Source = HeadPos;
+
+		// unused:
+		// ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&MidPos, PED_MID);
+		// Source - MidPos;
+
+		// Look around
+		bool UseMouse = false;
+		float MouseX = CPad::GetPad(0)->GetMouseX();
+		float MouseY = CPad::GetPad(0)->GetMouseY();
+		float LookLeftRight, LookUpDown;
+		if(MouseX != 0.0f || MouseY != 0.0f){
+			UseMouse = true;
+			LookLeftRight = -3.0f*MouseX;
+			LookUpDown = 4.0f*MouseY;
+		}else{
+			LookLeftRight = -CPad::GetPad(0)->LookAroundLeftRight();
+			LookUpDown = CPad::GetPad(0)->LookAroundUpDown();
+		}
+		if(UseMouse){
+			Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+			Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+		}else{
+			float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+			float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+			Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+			Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+		}
+		while(Beta >= PI) Beta -= 2*PI;
+		while(Beta < -PI) Beta += 2*PI;
+		if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+		if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+		TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+		TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+		TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+		Front = TargetCoors - Source;
+		Front.Normalise();
+		Source += Front*0.4f;
+
+		TheCamera.m_AlphaForPlayerAnim1rstPerson = Alpha;
+
+		GetVectorsReadyForRW();
+
+		float Heading = Front.Heading();
+		((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading;
+		((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading;
+		TheCamera.pTargetEntity->SetHeading(Heading);
+		TheCamera.pTargetEntity->GetMatrix().UpdateRW();
+
+		if(Mode == MODE_SNIPER_RUNABOUT){
+			// no mouse wheel FOV buffering here like in normal sniper mode
+			if(CPad::GetPad(0)->SniperZoomIn() || CPad::GetPad(0)->SniperZoomOut()){
+				if(CPad::GetPad(0)->SniperZoomOut())
+					FOV *= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+				else
+					FOV /= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+			}
+
+			TheCamera.SetMotionBlur(180, 255, 180, 120, MBLUR_SNIPER);
+
+			if(FOV > DefaultFOV)
+				FOV = DefaultFOV;
+			if(FOV < 15.0f)
+				FOV = 15.0f;
+		}
+	}
+
+	ResetStatics = false;
+	RwCameraSetNearClipPlane(Scene.camera, 0.05f);
+}
+
+void
+CCam::Process_Sniper(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	if(CamTargetEntity->m_rwObject == nil)
+		return;
+
+#ifdef FIX_BUGS
+	if(!CamTargetEntity->IsPed())
+		return;
+#endif
+
+	static bool FailedTestTwelveFramesAgo = false;
+	RwV3d HeadPos;
+	CVector TargetCoors;
+	TargetCoors = CameraTarget;
+
+	static float TargetFOV = 0.0f;
+
+	if(ResetStatics){
+		Beta = TargetOrientation;
+		Alpha = 0.0f;
+		m_fInitialPlayerOrientation = TargetOrientation;
+		FailedTestTwelveFramesAgo = false;
+		// static DPadVertical unused
+		// static DPadHorizontal unused
+		m_bCollisionChecksOn = true;
+		FOVSpeed = 0.0f;
+		TargetFOV = FOV;
+		ResetStatics = false;
+	}
+
+	((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD);
+	Source = HeadPos;
+	Source.z += 0.1f;
+	Source.x -= 0.19f*Cos(m_fInitialPlayerOrientation);
+	Source.y -= 0.19f*Sin(m_fInitialPlayerOrientation);
+
+	// Look around
+	bool UseMouse = false;
+	float MouseX = CPad::GetPad(0)->GetMouseX();
+	float MouseY = CPad::GetPad(0)->GetMouseY();
+	float LookLeftRight, LookUpDown;
+	if(MouseX != 0.0f || MouseY != 0.0f){
+		UseMouse = true;
+		LookLeftRight = -3.0f*MouseX;
+		LookUpDown = 4.0f*MouseY;
+	}else{
+		LookLeftRight = -CPad::GetPad(0)->SniperModeLookLeftRight();
+		LookUpDown = CPad::GetPad(0)->SniperModeLookUpDown();
+	}
+	if(UseMouse){
+		Beta += TheCamera.m_fMouseAccelHorzntl * LookLeftRight * FOV/80.0f;
+		Alpha += TheCamera.m_fMouseAccelVertical * LookUpDown * FOV/80.0f;
+	}else{
+		float xdir = LookLeftRight < 0.0f ? -1.0f : 1.0f;
+		float ydir = LookUpDown < 0.0f ? -1.0f : 1.0f;
+		Beta += SQR(LookLeftRight/100.0f)*xdir/17.5 * FOV/80.0f * CTimer::GetTimeStep();
+		Alpha += SQR(LookUpDown/150.0f)*ydir/14.0f * FOV/80.0f * CTimer::GetTimeStep();
+	}
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+	if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f);
+	if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f);
+
+	TargetCoors.x = 3.0f * Cos(Alpha) * Cos(Beta) + Source.x;
+	TargetCoors.y = 3.0f * Cos(Alpha) * Sin(Beta) + Source.y;
+	TargetCoors.z = 3.0f * Sin(Alpha) + Source.z;
+
+	UseMouse = false;
+	int ZoomInButton = ControlsManager.GetMouseButtonAssociatedWithAction(PED_SNIPER_ZOOM_IN);
+	int ZoomOutButton = ControlsManager.GetMouseButtonAssociatedWithAction(PED_SNIPER_ZOOM_OUT);
+	// TODO: enum? this should be mouse wheel up and down
+	if(ZoomInButton == 4 || ZoomInButton == 5 || ZoomOutButton == 4 || ZoomOutButton == 5){
+		if(CPad::GetPad(0)->GetMouseWheelUp() || CPad::GetPad(0)->GetMouseWheelDown()){
+			if(CPad::GetPad(0)->SniperZoomIn()){
+				TargetFOV = FOV - 10.0f;
+				UseMouse = true;
+			}
+			if(CPad::GetPad(0)->SniperZoomOut()){
+				TargetFOV = FOV + 10.0f;
+				UseMouse = true;
+			}
+		}
+	}
+	if((CPad::GetPad(0)->SniperZoomIn() || CPad::GetPad(0)->SniperZoomOut()) && !UseMouse){
+		if(CPad::GetPad(0)->SniperZoomOut()){
+			FOV *= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+			TargetFOV = FOV;
+			FOVSpeed = 0.0f;
+		}else{
+			FOV /= (255.0f*CTimer::GetTimeStep() + 10000.0f) / 10000.0f;
+			TargetFOV = FOV;
+			FOVSpeed = 0.0f;
+		}
+	}else{
+		if(Abs(TargetFOV - FOV) > 0.5f)
+			WellBufferMe(TargetFOV, &FOV, &FOVSpeed, 0.5f, 0.25f, false);
+		else
+			FOVSpeed = 0.0f;
+	}
+
+	TheCamera.SetMotionBlur(180, 255, 180, 120, MBLUR_SNIPER);
+
+	if(FOV > DefaultFOV)
+		FOV = DefaultFOV;
+	if(FOV < 15.0f)
+		FOV = 15.0f;
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	Source += Front*0.4f;
+
+	if(m_bCollisionChecksOn){
+		if(!CWorld::GetIsLineOfSightClear(TargetCoors, Source, true, true, false, true, false, true, true)){
+			RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+			FailedTestTwelveFramesAgo = true;
+		}else{
+			CVector TestPoint;
+			TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta + DEGTORAD(35.0f)) + Source.x;
+			TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta + DEGTORAD(35.0f)) + Source.y;
+			TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+			if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+				RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+				FailedTestTwelveFramesAgo = true;
+			}else{
+				TestPoint.x = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Cos(Beta - DEGTORAD(35.0f)) + Source.x;
+				TestPoint.y = 3.0f * Cos(Alpha - DEGTORAD(20.0f)) * Sin(Beta - DEGTORAD(35.0f)) + Source.y;
+				TestPoint.z = 3.0f * Sin(Alpha - DEGTORAD(20.0f)) + Source.z;
+				if(!CWorld::GetIsLineOfSightClear(TestPoint, Source, true, true, false, true, false, true, true)){
+					RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+					FailedTestTwelveFramesAgo = true;
+				}else
+					FailedTestTwelveFramesAgo = false;
+			}
+		}
+	}
+
+	if(FailedTestTwelveFramesAgo)
+		RwCameraSetNearClipPlane(Scene.camera, 0.4f);
+	Source -= Front*0.4f;
+
+	GetVectorsReadyForRW();
+	float Rotation = CGeneral::GetATanOfXY(Front.x, Front.y) - HALFPI;
+	((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Rotation;
+	((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Rotation;
+}
+
+void
+CCam::Process_Syphon(const CVector &CameraTarget, float, float, float)
+{
+	FOV = DefaultFOV;
+
+	if(!CamTargetEntity->IsPed())
+		return;
+
+	static bool CameraObscured = false;
+	// unused FailedClippingTestPrevously
+	static float BetaOffset = DEGTORAD(18.0f);
+	// unused AngleToGoTo
+	// unused AngleToGoToSpeed
+	// unused DistBetweenPedAndPlayerPreviouslyOn
+	static float HeightDown = -0.5f;
+	static float PreviousDistForInter;
+	CVector TargetCoors;
+	CVector2D vDist;
+	float fDist, fAimingDist;
+	float TargetAlpha;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	TargetCoors = CameraTarget;
+
+	if(TheCamera.Cams[TheCamera.ActiveCam].Mode != MODE_SYPHON)
+		return;
+
+	vDist = Source - TargetCoors;
+	fDist = vDist.Magnitude();
+	if(fDist == 0.0f)
+		Source = TargetCoors + CVector(1.0f, 1.0f, 0.0f);
+	else
+		Source = TargetCoors + CVector(vDist.x/fDist * 1.7f, vDist.y/fDist * 1.7f, 0.0f);
+	if(fDist > 1.7f)
+		fDist = 1.7f;
+
+	Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+
+	float NewBeta = CGeneral::GetATanOfXY(TheCamera.m_cvecAimingTargetCoors.x - TargetCoors.x, TheCamera.m_cvecAimingTargetCoors.y - TargetCoors.y) + PI;
+	if(ResetStatics){
+		CameraObscured = false;
+		float TestBeta1 = NewBeta - BetaOffset - Beta;
+		float TestBeta2 = NewBeta + BetaOffset - Beta;
+		MakeAngleLessThan180(TestBeta1);
+		MakeAngleLessThan180(TestBeta2);
+		if(Abs(TestBeta1) < Abs(TestBeta2))
+			BetaOffset = -BetaOffset;
+		// some unuseds
+		ResetStatics = false;
+	}
+	Beta = NewBeta + BetaOffset;
+	Source = TargetCoors;
+	Source.x += 1.7f*Cos(Beta);
+	Source.y += 1.7f*Sin(Beta);
+	TargetCoors.z += m_fSyphonModeTargetZOffSet;
+	fAimingDist = (TheCamera.m_cvecAimingTargetCoors - TargetCoors).Magnitude2D();
+	if(fAimingDist < 6.5f)
+		fAimingDist = 6.5f;
+	TargetAlpha = CGeneral::GetATanOfXY(fAimingDist, TheCamera.m_cvecAimingTargetCoors.z - TargetCoors.z);
+	while(TargetAlpha >= PI) TargetAlpha -= 2*PI;
+	while(TargetAlpha < -PI) TargetAlpha += 2*PI;
+
+	// inlined
+	WellBufferMe(-TargetAlpha, &Alpha, &AlphaSpeed, 0.07f, 0.015f, true);
+
+	Source.z += fDist*Sin(Alpha) + fDist*0.2f;
+	if(Source.z < TargetCoors.z + HeightDown)
+		Source.z = TargetCoors.z + HeightDown;
+
+	CameraObscured = CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true);
+	// PreviousDistForInter unused
+	if(CameraObscured){
+		PreviousDistForInter = (TargetCoors - colPoint.point).Magnitude2D();
+		Source = colPoint.point;
+	}else
+		PreviousDistForInter = 1.7f;
+
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+	Front = TargetCoors - Source;
+	m_fMinDistAwayFromCamWhenInterPolating = Front.Magnitude2D();
+	if(m_fMinDistAwayFromCamWhenInterPolating < 1.1f)
+		RwCameraSetNearClipPlane(Scene.camera, max(m_fMinDistAwayFromCamWhenInterPolating - 0.35f, 0.05f));
+	Front.Normalise();
+	GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_Syphon_Crim_In_Front(const CVector &CameraTarget, float, float, float)
+{
+	FOV = DefaultFOV;
+
+	if(!CamTargetEntity->IsPed())
+		return;
+
+	CVector TargetCoors = CameraTarget;
+	CVector vDist;
+	float fDist, TargetDist;
+	float zOffset;
+	float AimingAngle;
+	CColPoint colPoint;
+	CEntity *entity;
+
+	TargetDist = TheCamera.m_fPedZoomValueSmooth * 0.5f + 4.0f;
+	vDist = Source - TargetCoors;
+	fDist = vDist.Magnitude2D();
+	zOffset = TargetDist - 2.65f;
+	if(zOffset < 0.0f)
+		zOffset = 0.0f;
+	if(zOffset == 0.0f)
+		Source = TargetCoors + CVector(1.0f, 1.0f, zOffset);
+	else
+		Source = TargetCoors + CVector(vDist.x/fDist*TargetDist, vDist.y/fDist*TargetDist, zOffset);
+
+	AimingAngle = CGeneral::GetATanOfXY(TheCamera.m_cvecAimingTargetCoors.x - TargetCoors.x, TheCamera.m_cvecAimingTargetCoors.y - TargetCoors.y);
+	while(AimingAngle >= PI) AimingAngle -= 2*PI;
+	while(AimingAngle < -PI) AimingAngle += 2*PI;
+
+	if(TheCamera.PlayerWeaponMode.Mode == MODE_SYPHON)
+		Beta = AimingAngle + m_fPlayerInFrontSyphonAngleOffSet;
+
+	Source.x = TargetCoors.x;
+	Source.y = TargetCoors.y;
+	Source.x += Cos(Beta) * TargetDist;
+	Source.y += Sin(Beta) * TargetDist;
+
+	if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, true, false, false, true, false, true, true)){
+		Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
+		fDist = (TargetCoors - colPoint.point).Magnitude2D();
+		Source.x = TargetCoors.x;
+		Source.y = TargetCoors.y;
+		Source.x += Cos(Beta) * fDist;
+		Source.y += Sin(Beta) * fDist;
+	}
+
+	TargetCoors = CameraTarget;
+	TargetCoors.z += m_fSyphonModeTargetZOffSet;
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+	Front = TargetCoors - Source;
+	GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_BehindBoat(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	if(!CamTargetEntity->IsVehicle()){
+		ResetStatics = false;
+		return;
+	}
+
+	CVector TargetCoors = CameraTarget;
+	float DeltaBeta = 0.0f;
+	static CColPoint colPoint;
+	CEntity *entity;
+	static float TargetWhenChecksWereOn = 0.0f;
+	static float CenterObscuredWhenChecksWereOn = 0.0f;
+	static float WaterZAddition = 2.75f;
+	float WaterLevel = 0.0f;
+	float s, c;
+	float Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
+	FOV = DefaultFOV;
+
+	if(ResetStatics){
+		CenterObscuredWhenChecksWereOn = 0.0f;
+		TargetWhenChecksWereOn = 0.0f;
+		Beta = TargetOrientation + PI;
+	}
+
+	CWaterLevel::GetWaterLevelNoWaves(TargetCoors.x, TargetCoors.y, TargetCoors.z, &WaterLevel);
+	WaterLevel += WaterZAddition;
+	static float FixerForGoingBelowGround = 0.4f;
+	if(-FixerForGoingBelowGround < TargetCoors.z-WaterLevel)
+		WaterLevel += TargetCoors.z-WaterLevel - FixerForGoingBelowGround;
+
+	bool Obscured;
+	if(m_bCollisionChecksOn || ResetStatics){
+		CVector TestPoint;
+		// Weird calculations here, also casting bool to float...
+		c = Cos(TargetOrientation);
+		s = Sin(TargetOrientation);
+		TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+			(TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+			TargetCoors;
+		TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+		float Test1 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true);
+
+		c = Cos(TargetOrientation + 0.8f);
+		s = Sin(TargetOrientation + DEGTORAD(40.0f));
+		TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+			(TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+			TargetCoors;
+		TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+		float Test2 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true);
+
+		c = Cos(TargetOrientation - 0.8);
+		s = Sin(TargetOrientation - DEGTORAD(40.0f));
+		TestPoint = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+			(TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+			TargetCoors;
+		TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+		float Test3 = CWorld::GetIsLineOfSightClear(TestPoint, TargetCoors, true, false, false, true, false, true, true);
+
+		if(Test2 == 0.0f){
+			DeltaBeta = TargetOrientation - Beta - DEGTORAD(40.0f);
+			if(ResetStatics)
+				Beta = TargetOrientation - DEGTORAD(40.0f);
+		}else if(Test3 == 0.0f){
+			DeltaBeta = TargetOrientation - Beta + DEGTORAD(40.0f);
+			if(ResetStatics)
+				Beta = TargetOrientation + DEGTORAD(40.0f);
+		}else if(Test1 == 0.0f){
+			DeltaBeta = 0.0f;
+		}else if(Test2 != 0.0f && Test3 != 0.0f && Test1 != 0.0f){
+			if(ResetStatics)
+				Beta = TargetOrientation;
+			DeltaBeta = TargetOrientation - Beta;
+		}
+
+		c = Cos(Beta);
+		s = Sin(Beta);
+		TestPoint.x = TheCamera.CarZoomValueSmooth * -c +
+			(TheCamera.CarZoomValueSmooth + 7.0f) * -c +
+			TargetCoors.x;
+		TestPoint.y = TheCamera.CarZoomValueSmooth * -s +
+			(TheCamera.CarZoomValueSmooth + 7.0f) * -s +
+			TargetCoors.y;
+		TestPoint.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+		Obscured = CWorld::ProcessLineOfSight(TestPoint, TargetCoors, colPoint, entity, true, false, false, true, false, true, true);
+		CenterObscuredWhenChecksWereOn = Obscured;
+
+		// now DeltaBeta == TargetWhenChecksWereOn - Beta, which we need for WellBufferMe below
+		TargetWhenChecksWereOn = DeltaBeta + Beta;
+	}else{
+		// DeltaBeta = TargetWhenChecksWereOn - Beta;	// unneeded since we don't inline WellBufferMe
+		Obscured = CenterObscuredWhenChecksWereOn != 0.0f;
+	}
+
+	if(Obscured){
+		CWorld::ProcessLineOfSight(Source, TargetCoors, colPoint, entity, true, false, false, true, false, true, true);
+		Source = colPoint.point;
+	}else{
+		// inlined
+		WellBufferMe(TargetWhenChecksWereOn, &Beta, &BetaSpeed, 0.07f, 0.015f, true);
+
+		s = Sin(Beta);
+		c = Cos(Beta);
+		Source = TheCamera.CarZoomValueSmooth * CVector(-c, -s, 0.0f) +
+			(TheCamera.CarZoomValueSmooth+7.0f) * CVector(-c, -s, 0.0f) +
+			TargetCoors;
+		Source.z = WaterLevel + TheCamera.CarZoomValueSmooth;
+	}
+
+	if(TheCamera.CarZoomValueSmooth < 0.05f){
+		static float AmountUp = 2.2f;
+		TargetCoors.z += AmountUp * (0.0f - TheCamera.CarZoomValueSmooth);
+	}
+	TargetCoors.z += TheCamera.CarZoomValueSmooth + 0.5f;
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+	Front = TargetCoors - Source;
+	GetVectorsReadyForRW();
+	ResetStatics = false;
+}
+
+void
+CCam::Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	if(!CamTargetEntity->IsPed())
+		return;
+
+	FOV = DefaultFOV;
+	float BetaLeft, BetaRight, DeltaBetaLeft, DeltaBetaRight;
+	float BetaFix;
+	float Dist;
+	float BetaMaxSpeed = 0.015f;
+	float BetaAcceleration = 0.007f;
+	static bool PreviouslyFailedBuildingChecks = false;
+	float TargetCamHeight;
+	CVector TargetCoors;
+
+	m_fMinDistAwayFromCamWhenInterPolating = 4.0f;
+	Front = Source - CameraTarget;
+	Beta = CGeneral::GetATanOfXY(Front.x, Front.y);
+	while(TargetOrientation >= PI) TargetOrientation -= 2*PI;
+	while(TargetOrientation < -PI) TargetOrientation += 2*PI;
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+
+	// Figure out Beta
+	BetaLeft = TargetOrientation - HALFPI;
+	BetaRight = TargetOrientation + HALFPI;
+	DeltaBetaLeft = Beta - BetaLeft;
+	DeltaBetaRight = Beta - BetaRight;
+	while(DeltaBetaLeft >= PI) DeltaBetaLeft -= 2*PI;
+	while(DeltaBetaLeft < -PI) DeltaBetaLeft += 2*PI;
+	while(DeltaBetaRight >= PI) DeltaBetaRight -= 2*PI;
+	while(DeltaBetaRight < -PI) DeltaBetaRight += 2*PI;
+
+	if(ResetStatics){
+		if(Abs(DeltaBetaLeft) < Abs(DeltaBetaRight))
+			m_fTargetBeta = DeltaBetaLeft;
+		else
+			m_fTargetBeta = DeltaBetaRight;
+		m_fBufferedTargetOrientation = TargetOrientation;
+		m_fBufferedTargetOrientationSpeed = 0.0f;
+		m_bCollisionChecksOn = true;
+		BetaSpeed = 0.0f;
+	}else if(CPad::GetPad(0)->WeaponJustDown()){
+		if(Abs(DeltaBetaLeft) < Abs(DeltaBetaRight))
+			m_fTargetBeta = DeltaBetaLeft;
+		else
+			m_fTargetBeta = DeltaBetaRight;
+	}
+
+	// Check collisions
+	BetaFix = 0.0f;
+	Dist = Front.Magnitude2D();
+	if(m_bCollisionChecksOn || PreviouslyFailedBuildingChecks){
+		BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.25f, 0.0f, true, false, false, true, false);
+		if(BetaFix == 0.0f){
+			BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.5f, DEGTORAD(24.0f), true, false, false, true, false);
+			if(BetaFix == 0.0f)
+				BetaFix = GetPedBetaAngleForClearView(CameraTarget, Dist+0.5f, -DEGTORAD(24.0f), true, false, false, true, false);
+		}
+	}
+	if(BetaFix != 0.0f){
+		BetaMaxSpeed = 0.1f;
+		PreviouslyFailedBuildingChecks = true;
+		BetaAcceleration = 0.025f;
+		m_fTargetBeta = Beta + BetaFix;
+	}
+	WellBufferMe(m_fTargetBeta, &Beta, &BetaSpeed, BetaMaxSpeed, BetaAcceleration, true);
+
+	Source = CameraTarget + 4.0f*CVector(Cos(Beta), Sin(Beta), 0.0f);
+	Source.z -= 0.5f;
+
+	WellBufferMe(TargetOrientation, &m_fBufferedTargetOrientation, &m_fBufferedTargetOrientationSpeed, 0.07f, 0.004f, true);
+	TargetCoors = CameraTarget + 0.5f*CVector(Cos(m_fBufferedTargetOrientation), Sin(m_fBufferedTargetOrientation), 0.0f);
+
+	TargetCamHeight = CameraTarget.z - Source.z + max(m_fPedBetweenCameraHeightOffset, m_fRoadOffSet + m_fDimensionOfHighestNearCar) - 0.5f;
+	if(TargetCamHeight > m_fCamBufferedHeight)
+		WellBufferMe(TargetCamHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.15f, 0.04f, false);
+	else
+		WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.08f, 0.0175f, false);
+	Source.z += m_fCamBufferedHeight;
+
+	m_cvecTargetCoorsForFudgeInter = TargetCoors;
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	GetVectorsReadyForRW();
+
+	ResetStatics = false;
+}
+
+/*
+// Spline format is this, but game doesn't seem to use any kind of struct:
+struct Spline
+{
+	float numFrames;
+	struct {
+		float time;
+		float f[3];	// CVector for Vector spline
+	} frames[1];	// numFrames
+};
+*/
+
+// These two functions are pretty ugly
+
+#define MS(t) (uint32)((t)*1000.0f)
+
+void
+FindSplinePathPositionFloat(float *out, float *spline, uint32 time, uint32 &marker)
+{
+	// marker is at time
+	uint32 numFrames = spline[0];
+	uint32 timeDelta = MS(spline[marker] - spline[marker-4]);
+	uint32 endTime = MS(spline[4*(numFrames-1) + 1]);
+	if(time < endTime){
+		bool canAdvance = true;
+		if((marker-1)/4 > numFrames){
+			canAdvance = false;
+			marker = 4*(numFrames-1) + 1;
+		}
+		// skipping over small time deltas apparently?
+		while(timeDelta <= 75 && canAdvance){
+			marker += 4;
+			if((marker-1)/4 > numFrames){
+				canAdvance = false;
+				marker = 4*(numFrames-1) + 1;
+			}
+			timeDelta = (spline[marker] - spline[marker-4]) * 1000.0f;
+		}
+	}
+	float a = ((float)time - (float)MS(spline[marker-4])) / (float)MS(spline[marker] - spline[marker-4]);
+	a = clamp(a, 0.0f, 1.0f);
+	float b = 1.0f - a;
+	*out =	b*b*b * spline[marker-3] +
+		3.0f*a*b*b * spline[marker-1] +
+		3.0f*a*a*b * spline[marker+2] +
+		a*a*a * spline[marker+1];
+}
+
+void
+FindSplinePathPositionVector(CVector *out, float *spline, uint32 time, uint32 &marker)
+{
+	// marker is at time
+	uint32 numFrames = spline[0];
+	uint32 timeDelta = MS(spline[marker] - spline[marker-10]);
+	uint32 endTime = MS(spline[10*(numFrames-1) + 1]);
+	if(time < endTime){
+		bool canAdvance = true;
+		if((marker-1)/10 > numFrames){
+			canAdvance = false;
+			marker = 10*(numFrames-1) + 1;
+		}
+		// skipping over small time deltas apparently?
+		while(timeDelta <= 75 && canAdvance){
+			marker += 10;
+			if((marker-1)/10 > numFrames){
+				canAdvance = false;
+				marker = 10*(numFrames-1) + 1;
+			}
+			timeDelta = (spline[marker] - spline[marker-10]) * 1000.0f;
+		}
+	}
+
+	if((marker-1)/10 > numFrames){
+		printf("Arraymarker %i \n", marker);
+		printf("Path zero %i \n", numFrames);
+	}
+
+	float a = ((float)time - (float)MS(spline[marker-10])) / (float)MS(spline[marker] - spline[marker-10]);
+	a = clamp(a, 0.0f, 1.0f);
+	float b = 1.0f - a;
+	out->x =
+		b*b*b * spline[marker-9] +
+		3.0f*a*b*b * spline[marker-3] +
+		3.0f*a*a*b * spline[marker+4] +
+		a*a*a * spline[marker+1];
+	out->y =
+		b*b*b * spline[marker-8] +
+		3.0f*a*b*b * spline[marker-2] +
+		3.0f*a*a*b * spline[marker+5] +
+		a*a*a * spline[marker+2];
+	out->z =
+		b*b*b * spline[marker-7] +
+		3.0f*a*b*b * spline[marker-1] +
+		3.0f*a*a*b * spline[marker+6] +
+		a*a*a * spline[marker+3];
+	*out += TheCamera.m_vecCutSceneOffset;
+}
+
+void
+CCam::Process_FlyBy(const CVector&, float, float, float)
+{
+	float UpAngle = 0.0f;
+	static float FirstFOVValue = 0.0f;
+	static float PsuedoFOV;
+	static uint32 ArrayMarkerFOV;
+	static uint32 ArrayMarkerUp;
+	static uint32 ArrayMarkerSource;
+	static uint32 ArrayMarkerFront;
+
+	if(TheCamera.m_bcutsceneFinished)
+		return;
+
+	Up = CVector(0.0f, 0.0f, 1.0f);
+	if(TheCamera.m_bStartingSpline)
+		m_fTimeElapsedFloat += CTimer::GetTimeStepInMilliseconds();
+	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]);
+		TheCamera.m_bStartingSpline = true;
+		FirstFOVValue = TheCamera.m_arrPathArray[0].m_arr_PathData[2];
+		PsuedoFOV = TheCamera.m_arrPathArray[0].m_arr_PathData[2];
+		ArrayMarkerFOV = 5;
+		ArrayMarkerUp = 5;
+		ArrayMarkerSource = 11;
+		ArrayMarkerFront = 11;
+	}
+
+	float fTime = m_fTimeElapsedFloat;
+	uint32 uiFinishTime = m_uiFinishTime;
+	uint32 uiTime = fTime;
+	if(uiTime < uiFinishTime){
+		TheCamera.m_fPositionAlongSpline = (float) uiTime / uiFinishTime;
+
+		while(uiTime >= (TheCamera.m_arrPathArray[2].m_arr_PathData[ArrayMarkerSource] - TheCamera.m_arrPathArray[2].m_arr_PathData[1])*1000.0f)
+			ArrayMarkerSource += 10;
+		FindSplinePathPositionVector(&Source, TheCamera.m_arrPathArray[2].m_arr_PathData, uiTime, ArrayMarkerSource);
+
+		while(uiTime >= (TheCamera.m_arrPathArray[3].m_arr_PathData[ArrayMarkerFront] - TheCamera.m_arrPathArray[3].m_arr_PathData[1])*1000.0f)
+			ArrayMarkerFront += 10;
+		FindSplinePathPositionVector(&Front, TheCamera.m_arrPathArray[3].m_arr_PathData, uiTime, ArrayMarkerFront);
+
+		while(uiTime >= (TheCamera.m_arrPathArray[1].m_arr_PathData[ArrayMarkerUp] - TheCamera.m_arrPathArray[1].m_arr_PathData[1])*1000.0f)
+			ArrayMarkerUp += 4;
+		FindSplinePathPositionFloat(&UpAngle, TheCamera.m_arrPathArray[1].m_arr_PathData, uiTime, ArrayMarkerUp);
+		UpAngle = DEGTORAD(UpAngle) + HALFPI;
+		Up.x = Cos(UpAngle);
+		Up.z = Sin(UpAngle);
+
+		while(uiTime >= (TheCamera.m_arrPathArray[0].m_arr_PathData[ArrayMarkerFOV] - TheCamera.m_arrPathArray[0].m_arr_PathData[1])*1000.0f)
+			ArrayMarkerFOV += 4;
+		FindSplinePathPositionFloat(&PsuedoFOV, TheCamera.m_arrPathArray[0].m_arr_PathData, uiTime, ArrayMarkerFOV);
+
+		m_cvecTargetCoorsForFudgeInter = Front;
+		Front = Front - Source;
+		Front.Normalise();
+		CVector Left = CrossProduct(Up, Front);
+		Up = CrossProduct(Front, Left);
+		Up.Normalise();
+		FOV = PsuedoFOV;
+	}else{
+		// end
+		ArrayMarkerSource = (TheCamera.m_arrPathArray[2].m_arr_PathData[0] - 1)*10 + 1;
+		ArrayMarkerFront = (TheCamera.m_arrPathArray[3].m_arr_PathData[0] - 1)*10 + 1;
+		ArrayMarkerUp = (TheCamera.m_arrPathArray[1].m_arr_PathData[0] - 1)*4 + 1;
+		ArrayMarkerFOV = (TheCamera.m_arrPathArray[0].m_arr_PathData[0] - 1)*4 + 1;
+
+		FindSplinePathPositionVector(&Source, TheCamera.m_arrPathArray[2].m_arr_PathData, uiTime, ArrayMarkerSource);
+		FindSplinePathPositionVector(&Front, TheCamera.m_arrPathArray[3].m_arr_PathData, uiTime, ArrayMarkerFront);
+		FindSplinePathPositionFloat(&UpAngle, TheCamera.m_arrPathArray[1].m_arr_PathData, uiTime, ArrayMarkerUp);
+		UpAngle = DEGTORAD(UpAngle) + HALFPI;
+		Up.x = Cos(UpAngle);
+		Up.z = Sin(UpAngle);
+		FindSplinePathPositionFloat(&PsuedoFOV, TheCamera.m_arrPathArray[0].m_arr_PathData, uiTime, ArrayMarkerFOV);
+
+		TheCamera.m_fPositionAlongSpline = 1.0f;
+		ArrayMarkerFOV = 0;
+		ArrayMarkerUp = 0;
+		ArrayMarkerSource = 0;
+		ArrayMarkerFront = 0;
+
+		m_cvecTargetCoorsForFudgeInter = Front;
+		Front = Front - Source;
+		Front.Normalise();
+		CVector Left = CrossProduct(Up, Front);
+		Up = CrossProduct(Front, Left);
+		Up.Normalise();
+		FOV = PsuedoFOV;
+	}
+}
+
+void
+CCam::Process_WheelCam(const CVector&, float, float, float)
+{
+	FOV = DefaultFOV;
+
+	if(CamTargetEntity->IsPed()){
+		// what? ped with wheels or what?
+		Source = Multiply3x3(CamTargetEntity->GetMatrix(), CVector(-0.3f, -0.5f, 0.1f));
+		Source += CamTargetEntity->GetPosition();
+		Front = CVector(1.0f, 0.0f, 0.0f);
+	}else{
+		Source = Multiply3x3(CamTargetEntity->GetMatrix(), CVector(-1.4f, -2.3f, 0.3f));
+		Source += CamTargetEntity->GetPosition();
+		Front = CamTargetEntity->GetForward();
+	}
+
+	CVector NewUp(0.0f, 0.0f, 1.0f);
+	CVector Left = CrossProduct(Front, NewUp);
+	Left.Normalise();
+	NewUp = CrossProduct(Left, Front);
+
+	float Roll = Cos((CTimer::GetTimeInMilliseconds()&0x1FFFF)/(float)0x1FFFF * TWOPI);
+	Up = Cos(Roll*0.4f)*NewUp + Sin(Roll*0.4f)*Left;
+}
+
+void
+CCam::Process_Fixed(const CVector &CameraTarget, float, float, float)
+{
+	Source = m_cvecCamFixedModeSource;
+	Front = CameraTarget - Source;
+	m_cvecTargetCoorsForFudgeInter = CameraTarget;
+	GetVectorsReadyForRW();
+
+	Up = CVector(0.0f, 0.0f, 1.0f) + m_cvecCamFixedModeUpOffSet;
+	Up.Normalise();
+	CVector Right = CrossProduct(Front, Up);
+	Right.Normalise();
+	Up = CrossProduct(Right, Front);
+
+	FOV = DefaultFOV;
+	if(TheCamera.m_bUseSpecialFovTrain)
+		FOV = TheCamera.m_fFovForTrain;
+
+	if(CMenuManager::m_ControlMethod == 0 && Using3rdPersonMouseCam()){
+		CPed *player = FindPlayerPed();
+		if(player && player->CanStrafeOrMouseControl()){
+			float Heading = Front.Heading();
+			((CPed*)TheCamera.pTargetEntity)->m_fRotationCur = Heading;
+			((CPed*)TheCamera.pTargetEntity)->m_fRotationDest = Heading;
+			TheCamera.pTargetEntity->SetHeading(Heading);
+			TheCamera.pTargetEntity->GetMatrix().UpdateRW();
+		}
+	}
+}
+
+void
+CCam::Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	CColPoint colPoint;
+	CEntity *entity = nil;
+
+	FOV = DefaultFOV;
+	Source = CameraTarget;
+	Source.x += -4.5f*Cos(TargetOrientation);
+	Source.y += -4.5f*Sin(TargetOrientation);
+	Source.z = m_vecLastAboveWaterCamPosition.z + 4.0f;
+
+	m_cvecTargetCoorsForFudgeInter = CameraTarget;
+	Front = CameraTarget - Source;
+	Front.Normalise();
+	if(CWorld::ProcessLineOfSight(CameraTarget, Source, colPoint, entity, true, false, false, true, false, true, true))
+		Source = colPoint.point;
+	GetVectorsReadyForRW();
+	Front = CameraTarget - Source;
+	Front.Normalise();
+}
+
+// unused
+void
+CCam::Process_Circle(const CVector &CameraTarget, float, float, float)
+{
+	FOV = DefaultFOV;
+
+	Front.x =  Cos(0.7f) * Cos((CTimer::GetTimeInMilliseconds()&0xFFF)/(float)0xFFF * TWOPI);
+	Front.y =  Cos(0.7f) * Sin((CTimer::GetTimeInMilliseconds()&0xFFF)/(float)0xFFF * TWOPI);
+	Front.z = -Sin(0.7f);
+	Source = CameraTarget - 4.0f*Front;
+	Source.z += 1.0f;
+	GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float)
+{
+	Source = m_cvecCamFixedModeSource;
+	m_cvecTargetCoorsForFudgeInter = CameraTarget;
+	m_cvecTargetCoorsForFudgeInter.z += m_fSyphonModeTargetZOffSet;
+	Front = CameraTarget - Source;
+	Front.z += m_fSyphonModeTargetZOffSet;
+
+	GetVectorsReadyForRW();
+
+	Up += m_cvecCamFixedModeUpOffSet;
+	Up.Normalise();
+	CVector Left = CrossProduct(Up, Front);
+	Left.Normalise();
+	Front = CrossProduct(Left, Up);
+	Front.Normalise();
+	FOV = DefaultFOV;
+}
+
+#ifdef IMPROVED_CAMERA
+
+#define KEYJUSTDOWN(k) ControlsManager.GetIsKeyboardKeyJustDown((RsKeyCodes)k)
+#define KEYDOWN(k) ControlsManager.GetIsKeyboardKeyDown((RsKeyCodes)k)
+#define CTRLJUSTDOWN(key) \
+	       ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \
+	        (KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+#define CTRLDOWN(key) ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+
+
+void
+CCam::Process_Debug(const CVector&, float, float, float)
+{
+	static float Speed = 0.0f;
+	static float PanSpeedX = 0.0f;
+	static float PanSpeedY = 0.0f;
+	CVector TargetCoors;
+
+	RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+	FOV = DefaultFOV;
+	Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f;
+	Beta  += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f;
+	if(CPad::GetPad(0)->GetLeftMouse()){
+		Alpha += DEGTORAD(CPad::GetPad(0)->GetMouseY()/2.0f);
+		Beta -= DEGTORAD(CPad::GetPad(0)->GetMouseX()/2.0f);
+	}
+
+	TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 3.0f;
+	TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 3.0f;
+	TargetCoors.z = Source.z + Sin(Alpha) * 3.0f;
+
+	if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f);
+	if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f);
+
+	if(CPad::GetPad(1)->GetSquare() || KEYDOWN('W'))
+		Speed += 0.1f;
+	else if(CPad::GetPad(1)->GetCross() || KEYDOWN('S'))
+		Speed -= 0.1f;
+	else
+		Speed = 0.0f;
+	if(Speed > 70.0f) Speed = 70.0f;
+	if(Speed < -70.0f) Speed = -70.0f;
+
+
+	if(KEYDOWN(rsRIGHT) || KEYDOWN('D'))
+		PanSpeedX += 0.1f;
+	else if(KEYDOWN(rsLEFT) || KEYDOWN('A'))
+		PanSpeedX -= 0.1f;
+	else
+		PanSpeedX = 0.0f;
+	if(PanSpeedX > 70.0f) PanSpeedX = 70.0f;
+	if(PanSpeedX < -70.0f) PanSpeedX = -70.0f;
+
+
+	if(KEYDOWN(rsUP))
+		PanSpeedY += 0.1f;
+	else if(KEYDOWN(rsDOWN))
+		PanSpeedY -= 0.1f;
+	else
+		PanSpeedY = 0.0f;
+	if(PanSpeedY > 70.0f) PanSpeedY = 70.0f;
+	if(PanSpeedY < -70.0f) PanSpeedY = -70.0f;
+
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	Source = Source + Front*Speed;
+
+	Up = CVector{ 0.0f, 0.0f, 1.0f };
+	CVector Right = CrossProduct(Front, Up);
+	Up = CrossProduct(Right, Front);
+	Source = Source + Up*PanSpeedY + Right*PanSpeedX;
+
+	if(Source.z < -450.0f)
+		Source.z = -450.0f;
+
+	if(CPad::GetPad(1)->GetRightShoulder2JustDown() || KEYJUSTDOWN(rsENTER)){
+		if(FindPlayerVehicle())
+			FindPlayerVehicle()->Teleport(Source);
+		else
+			CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source;	
+	}
+
+	// stay inside sectors
+	while(CWorld::GetSectorX(Source.x) > 95.0f)
+		Source.x -= 1.0f;
+	while(CWorld::GetSectorX(Source.x) < 5.0f)
+		Source.x += 1.0f;
+	while(CWorld::GetSectorY(Source.y) > 95.0f)
+		Source.y -= 1.0f;
+	while(CWorld::GetSectorY(Source.y) < 5.0f)
+		Source.y += 1.0f;
+	GetVectorsReadyForRW();
+
+	CPad::GetPad(0)->DisablePlayerControls = PLAYERCONTROL_DISABLED_1;
+
+	if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
+		CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
+			12.0f, 0.0f, 0.0f, -12.0f,
+			128, 128, 128, 128, 1000.0f, false, 1.0f);
+
+	if(CHud::m_Wants_To_Draw_Hud){
+		char str[256];
+		sprintf(str, "CamX: %f CamY: %f  CamZ:  %f", Source.x, Source.y, Source.z);
+		sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z);
+		sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z);
+	}
+}
+#else
+void
+CCam::Process_Debug(const CVector&, float, float, float)
+{
+	static float Speed = 0.0f;
+	CVector TargetCoors;
+
+	RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+	FOV = DefaultFOV;
+	Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f;
+	Beta  += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f;
+
+	TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 3.0f;
+	TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 3.0f;
+	TargetCoors.z = Source.z + Sin(Alpha) * 3.0f;
+
+	if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f);
+	if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f);
+
+	if(CPad::GetPad(1)->GetSquare() || CPad::GetPad(1)->GetLeftMouse())
+		Speed += 0.1f;
+	else if(CPad::GetPad(1)->GetCross() || CPad::GetPad(1)->GetRightMouse())
+		Speed -= 0.1f;
+	else
+		Speed = 0.0f;
+	if(Speed > 70.0f) Speed = 70.0f;
+	if(Speed < -70.0f) Speed = -70.0f;
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	Source = Source + Front*Speed;
+
+	if(Source.z < -450.0f)
+		Source.z = -450.0f;
+
+	if(CPad::GetPad(1)->GetRightShoulder2JustDown()){
+		if(FindPlayerVehicle())
+			FindPlayerVehicle()->Teleport(Source);
+		else
+			CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source;
+			
+	}
+
+	// stay inside sectors
+	while(CWorld::GetSectorX(Source.x) > 95.0f)
+		Source.x -= 1.0f;
+	while(CWorld::GetSectorX(Source.x) < 5.0f)
+		Source.x += 1.0f;
+	while(CWorld::GetSectorY(Source.y) > 95.0f)
+		Source.y -= 1.0f;
+	while(CWorld::GetSectorY(Source.y) < 5.0f)
+		Source.y += 1.0f;
+	GetVectorsReadyForRW();
+
+	if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
+		CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
+			12.0f, 0.0f, 0.0f, -12.0f,
+			128, 128, 128, 128, 1000.0f, false, 1.0f);
+
+	if(CHud::m_Wants_To_Draw_Hud){
+		char str[256];
+		sprintf(str, "CamX: %f CamY: %f  CamZ:  %f", Source.x, Source.y, Source.z);
+		sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z);
+		sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z);
+	}
+}
+#endif
+
+void
+CCam::Process_Editor(const CVector&, float, float, float)
+{
+	static float Speed = 0.0f;
+	CVector TargetCoors;
+
+	if(ResetStatics){
+		Source = CVector(796.0f, -937.0, 40.0f);
+		CamTargetEntity = nil;
+	}
+	ResetStatics = false;
+
+	RwCameraSetNearClipPlane(Scene.camera, 0.9f);
+	FOV = DefaultFOV;
+	Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f;
+	Beta  += DEGTORAD(CPad::GetPad(1)->GetLeftStickX())*1.5f / 19.0f;
+
+	if(CamTargetEntity && CSceneEdit::m_bCameraFollowActor){
+		TargetCoors = CamTargetEntity->GetPosition();
+	}else if(CSceneEdit::m_bRecording){
+		TargetCoors.x = Source.x + Cos(Alpha) * Cos(Beta) * 7.0f;
+		TargetCoors.y = Source.y + Cos(Alpha) * Sin(Beta) * 7.0f;
+		TargetCoors.z = Source.z + Sin(Alpha) * 7.0f;
+	}else
+		TargetCoors = CSceneEdit::m_vecCamHeading + Source;
+	CSceneEdit::m_vecCurrentPosition = TargetCoors;
+	CSceneEdit::m_vecCamHeading = TargetCoors - Source;
+
+	if(Alpha > DEGTORAD(89.5f)) Alpha = DEGTORAD(89.5f);
+	if(Alpha < DEGTORAD(-89.5f)) Alpha = DEGTORAD(-89.5f);
+
+	if(CPad::GetPad(1)->GetSquare() || CPad::GetPad(1)->GetLeftMouse())
+		Speed += 0.1f;
+	else if(CPad::GetPad(1)->GetCross() || CPad::GetPad(1)->GetRightMouse())
+		Speed -= 0.1f;
+	else
+		Speed = 0.0f;
+	if(Speed > 70.0f) Speed = 70.0f;
+	if(Speed < -70.0f) Speed = -70.0f;
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	Source = Source + Front*Speed;
+
+	if(Source.z < -450.0f)
+		Source.z = -450.0f;
+
+	if(CPad::GetPad(1)->GetRightShoulder2JustDown()){
+		if(FindPlayerVehicle())
+			FindPlayerVehicle()->Teleport(Source);
+		else
+			CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source;
+			
+	}
+
+	// stay inside sectors
+	while(CWorld::GetSectorX(Source.x) > 95.0f)
+		Source.x -= 1.0f;
+	while(CWorld::GetSectorX(Source.x) < 5.0f)
+		Source.x += 1.0f;
+	while(CWorld::GetSectorY(Source.y) > 95.0f)
+		Source.y -= 1.0f;
+	while(CWorld::GetSectorY(Source.y) < 5.0f)
+		Source.y += 1.0f;
+	GetVectorsReadyForRW();
+
+	if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
+		CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
+			12.0f, 0.0f, 0.0f, -12.0f,
+			128, 128, 128, 128, 1000.0f, false, 1.0f);
+
+	if(CHud::m_Wants_To_Draw_Hud){
+		char str[256];
+		sprintf(str, "CamX: %f CamY: %f  CamZ:  %f", Source.x, Source.y, Source.z);
+		sprintf(str, "Frontx: %f, Fronty: %f, Frontz: %f ", Front.x, Front.y, Front.z);
+		sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z);
+	}
+}
+
+void
+CCam::Process_ModelView(const CVector &CameraTarget, float, float, float)
+{
+	CVector TargetCoors = CameraTarget;
+	float Angle = Atan2(Front.x, Front.y);
+	FOV = DefaultFOV;
+
+	Angle += CPad::GetPad(0)->GetLeftStickX()/1280.0f;
+	if(Distance < 10.0f)
+		Distance += CPad::GetPad(0)->GetLeftStickY()/1000.0f;
+	else
+		Distance += CPad::GetPad(0)->GetLeftStickY() * ((Distance - 10.0f)/20.0f + 1.0f) / 1000.0f;
+	if(Distance < 1.5f)
+		Distance = 1.5f;
+
+	Front.x = Cos(0.3f) * Sin(Angle);
+	Front.y = Cos(0.3f) * Cos(Angle);
+	Front.z = -Sin(0.3f);
+	Source = CameraTarget - Distance*Front;
+
+	GetVectorsReadyForRW();
+}
+
+void
+CCam::ProcessPedsDeadBaby(void)
+{
+	float Distance = 0.0f;
+	static bool SafeToRotate = false;
+	CVector TargetDist, TestPoint;
+
+	FOV = DefaultFOV;
+	TargetDist = Source - CamTargetEntity->GetPosition();
+	Distance = TargetDist.Magnitude();
+	Beta = CGeneral::GetATanOfXY(TargetDist.x, TargetDist.y);
+	while(Beta >= PI) Beta -= 2*PI;
+	while(Beta < -PI) Beta += 2*PI;
+
+	if(ResetStatics){
+		TestPoint = CamTargetEntity->GetPosition() +
+			CVector(4.0f * Cos(Alpha) * Cos(Beta),
+			        4.0f * Cos(Alpha) * Sin(Beta),
+			        4.0f * Sin(Alpha));
+		bool Safe1 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true);
+
+		TestPoint = CamTargetEntity->GetPosition() +
+			CVector(4.0f * Cos(Alpha) * Cos(Beta + DEGTORAD(120.0f)),
+			        4.0f * Cos(Alpha) * Sin(Beta + DEGTORAD(120.0f)),
+			        4.0f * Sin(Alpha));
+		bool Safe2 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true);
+
+		TestPoint = CamTargetEntity->GetPosition() +
+			CVector(4.0f * Cos(Alpha) * Cos(Beta - DEGTORAD(120.0f)),
+			        4.0f * Cos(Alpha) * Sin(Beta - DEGTORAD(120.0f)),
+			        4.0f * Sin(Alpha));
+		bool Safe3 = CWorld::GetIsLineOfSightClear(TestPoint, CamTargetEntity->GetPosition(), true, false, false, true, false, true, true);
+
+		SafeToRotate = Safe1 && Safe2 && Safe3;
+
+		ResetStatics = false;
+	}
+
+	if(SafeToRotate)
+		WellBufferMe(Beta + DEGTORAD(175.0f), &Beta, &BetaSpeed, 0.015f, 0.007f, true);
+
+	WellBufferMe(DEGTORAD(89.5f), &Alpha, &AlphaSpeed, 0.015f, 0.07f, true);
+	WellBufferMe(35.0f, &Distance, &DistanceSpeed, 0.006f, 0.007f, false);
+
+	Source = CamTargetEntity->GetPosition() +
+		CVector(Distance * Cos(Alpha) * Cos(Beta),
+		        Distance * Cos(Alpha) * Sin(Beta),
+		        Distance * Sin(Alpha));
+	m_cvecTargetCoorsForFudgeInter = CamTargetEntity->GetPosition();
+	Front = CamTargetEntity->GetPosition() - Source;
+	Front.Normalise();
+	GetVectorsReadyForRW();
+}
+
+bool
+CCam::ProcessArrestCamOne(void)
+{
+	FOV = 45.0f;
+	if(ResetStatics)
+		return true;
+
+#ifdef FIX_BUGS
+	if(!CamTargetEntity->IsPed())
+		return true;
+#endif
+
+	bool found;
+	float Ground;
+	CVector PlayerCoors = TheCamera.pTargetEntity->GetPosition();
+	CVector CopCoors = ((CPlayerPed*)TheCamera.pTargetEntity)->m_pArrestingCop->GetPosition();
+	Beta = CGeneral::GetATanOfXY(PlayerCoors.x - CopCoors.x, PlayerCoors.y - CopCoors.y);
+
+	Source = PlayerCoors + 9.5f*CVector(Cos(Beta), Sin(Beta), 0.0f);
+	Source.z += 6.0f;
+	Ground = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, Source.z, &found);
+	if(!found){
+		Ground = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, Source.z, &found);
+		if(!found)
+			return false;
+	}
+	Source.z = Ground + 0.25f;
+	if(!CWorld::GetIsLineOfSightClear(Source, CopCoors, true, true, false, true, false, true, true)){
+		Beta += DEGTORAD(115.0f);
+		Source = PlayerCoors + 9.5f*CVector(Cos(Beta), Sin(Beta), 0.0f);
+		Source.z += 6.0f;
+		Ground = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, Source.z, &found);
+		if(!found){
+			Ground = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, Source.z, &found);
+			if(!found)
+				return false;
+		}
+		Source.z = Ground + 0.25f;
+
+		CopCoors.z += 0.35f;
+		Front = CopCoors - Source;
+		if(!CWorld::GetIsLineOfSightClear(Source, CopCoors, true, true, false, true, false, true, true))
+			return false;
+	}
+	CopCoors.z += 0.35f;
+	m_cvecTargetCoorsForFudgeInter = CopCoors;
+	Front = CopCoors - Source;
+	ResetStatics = false;
+	GetVectorsReadyForRW();
+	return true;
+}
+
+bool
+CCam::ProcessArrestCamTwo(void)
+{
+	CPed *player = CWorld::Players[CWorld::PlayerInFocus].m_pPed;
+	if(!ResetStatics)
+		return true;
+	ResetStatics = false;
+
+	CVector TargetCoors, ToCamera;
+	float BetaOffset;
+	float SourceX, SourceY;
+	CCam *ActiveCam = &TheCamera.Cams[TheCamera.ActiveCam];
+	if(&ActiveCam[1] == this){
+		SourceX = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.x;
+		SourceY = TheCamera.Cams[(TheCamera.ActiveCam + 1) % 2].Source.y;
+	}else{
+		SourceX = ActiveCam[1].Source.x;
+		SourceY = ActiveCam[1].Source.y;
+	}
+
+	for(int i = 0; i <= 1; i++){
+		int Dir = i == 0 ? 1 : -1;
+
+		TargetCoors = player->GetPosition();
+		Beta = CGeneral::GetATanOfXY(TargetCoors.x-SourceX, TargetCoors.y-SourceY);
+		BetaOffset = DEGTORAD(Dir*80);
+		Source = TargetCoors + 11.5f*CVector(Cos(Beta+BetaOffset), Sin(Beta+BetaOffset), 0.0f);
+
+		ToCamera = Source - TargetCoors;
+		ToCamera.Normalise();
+		TargetCoors.x += 0.4f*ToCamera.x;
+		TargetCoors.y += 0.4f*ToCamera.y;
+		if(CWorld::GetIsLineOfSightClear(Source, TargetCoors, true, true, false, true, false, true, true)){
+			Source.z += 5.5f;
+			TargetCoors += CVector(-0.8f*ToCamera.x, -0.8f*ToCamera.y, 2.2f);
+			m_cvecTargetCoorsForFudgeInter = TargetCoors;
+			Front = TargetCoors - Source;
+			ResetStatics = false;
+			GetVectorsReadyForRW();
+			return true;
+		}
+	}
+	return false;
+}
+
+
+/*
+ * Unused PS2 cams
+ */
+
+void
+CCam::Process_Chris_With_Binding_PlusRotation(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	static float AngleToBinned = 0.0f;
+	static float StartingAngleLastChange = 0.0f;
+	static float FixedTargetOrientation = 0.0f;
+	static float DeadZoneReachedOnePrevious;
+
+	FOV = DefaultFOV;	// missing in game
+
+	bool FixOrientation = true;
+	if(ResetStatics){
+		Rotating = false;
+		DeadZoneReachedOnePrevious = 0.0f;
+		FixedTargetOrientation = 0.0f;
+		ResetStatics = false;
+	}
+
+	CVector TargetCoors = CameraTarget;
+
+	float StickX = CPad::GetPad(0)->GetRightStickX();
+	float StickY = CPad::GetPad(0)->GetRightStickY();
+	float StickAngle;
+	if(StickX != 0.0 || StickY != 0.0f)	// BUG: game checks StickX twice
+		StickAngle = CGeneral::GetATanOfXY(StickX, StickY);	// result unused?
+	else
+		FixOrientation = false;
+
+	CVector Dist = Source - TargetCoors;
+	Source.z = TargetCoors.z + 0.75f;
+	float Length = Dist.Magnitude2D();
+	if(Length > 2.5f){
+		Source.x = TargetCoors.x + Dist.x/Length * 2.5f;
+		Source.y = TargetCoors.y + Dist.y/Length * 2.5f;
+	}else if(Length < 2.4f){
+		Source.x = TargetCoors.x + Dist.x/Length * 2.4f;
+		Source.y = TargetCoors.y + Dist.y/Length * 2.4f;
+	}
+
+	Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+	if(CPad::GetPad(0)->GetLeftShoulder1()){
+		FixedTargetOrientation = TargetOrientation;
+		Rotating = true;
+	}
+
+	if(FixOrientation){
+		Rotating = true;
+		FixedTargetOrientation = StickX/128.0f + Beta - PI;
+	}
+
+	if(Rotating){
+		Dist = Source - TargetCoors;
+		Length = Dist.Magnitude2D();
+		// inlined
+		WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true);
+
+		Source.x = TargetCoors.x + Length*Cos(Beta);
+		Source.y = TargetCoors.y + Length*Sin(Beta);
+
+		float DeltaBeta = FixedTargetOrientation+PI - Beta;
+		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+		if(Abs(DeltaBeta) < 0.06f)
+			Rotating = false;
+	}
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	CVector Front2 = Front;
+	Front2.Normalise();	// What?
+	// FIX: the meaning of this value must have changed somehow
+	Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f;
+//	Source += Front2 * TheCamera.m_fPedZoomValueSmooth;
+
+	GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_ReactionCam(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	static float AngleToBinned = 0.0f;
+	static float StartingAngleLastChange = 0.0f;
+	static float FixedTargetOrientation;
+	static float DeadZoneReachedOnePrevious;
+	static uint32 TimeOfLastChange;
+	uint32 Time;
+	bool DontBind = false;	// BUG: left uninitialized
+
+	FOV = DefaultFOV;	// missing in game
+
+	if(ResetStatics){
+		Rotating = false;
+		DeadZoneReachedOnePrevious = 0.0f;
+		FixedTargetOrientation = 0.0f;
+		ResetStatics = false;
+		DontBind = false;
+	}
+
+	CVector TargetCoors = CameraTarget;
+
+	CVector Dist = Source - TargetCoors;
+	Source.z = TargetCoors.z + 0.75f;
+	float Length = Dist.Magnitude2D();
+	if(Length > 2.5f){
+		Source.x = TargetCoors.x + Dist.x/Length * 2.5f;
+		Source.y = TargetCoors.y + Dist.y/Length * 2.5f;
+	}else if(Length < 2.4f){
+		Source.x = TargetCoors.x + Dist.x/Length * 2.4f;
+		Source.y = TargetCoors.y + Dist.y/Length * 2.4f;
+	}
+
+	Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+
+	float StickX = CPad::GetPad(0)->GetLeftStickX();
+	float StickY = CPad::GetPad(0)->GetLeftStickY();
+	float StickAngle;
+	if(StickX != 0.0 || StickY != 0.0f){
+		StickAngle = CGeneral::GetATanOfXY(StickX, StickY);
+		while(StickAngle >= PI) StickAngle -= 2*PI;
+		while(StickAngle < -PI) StickAngle += 2*PI;
+	}else
+		StickAngle = 1000.0f;
+
+	if(Abs(StickAngle-AngleToBinned) > DEGTORAD(15.0f)){
+		DontBind = true;
+		Time = CTimer::GetTimeInMilliseconds();
+	}
+
+	if(CTimer::GetTimeInMilliseconds()-TimeOfLastChange > 200){
+		if(Abs(HALFPI-StickAngle) > DEGTORAD(50.0f)){
+			FixedTargetOrientation = TargetOrientation;
+			Rotating = true;
+			TimeOfLastChange = CTimer::GetTimeInMilliseconds();
+		}
+	}
+
+	// These two together don't make much sense.
+	// Only prevents rotation for one frame
+	AngleToBinned = StickAngle;
+	if(DontBind)
+		TimeOfLastChange = Time;
+
+	if(Rotating){
+		Dist = Source - TargetCoors;
+		Length = Dist.Magnitude2D();
+		// inlined
+		WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true);
+
+		Source.x = TargetCoors.x + Length*Cos(Beta);
+		Source.y = TargetCoors.y + Length*Sin(Beta);
+
+		float DeltaBeta = FixedTargetOrientation+PI - Beta;
+		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+		if(Abs(DeltaBeta) < 0.06f)
+			Rotating = false;
+	}
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	CVector Front2 = Front;
+	Front2.Normalise();	// What?
+	// FIX: the meaning of this value must have changed somehow
+	Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f;
+//	Source += Front2 * TheCamera.m_fPedZoomValueSmooth;
+
+	GetVectorsReadyForRW();
+}
+
+void
+CCam::Process_FollowPed_WithBinding(const CVector &CameraTarget, float TargetOrientation, float, float)
+{
+	static float AngleToBinned = 0.0f;
+	static float StartingAngleLastChange = 0.0f;
+	static float FixedTargetOrientation;
+	static float DeadZoneReachedOnePrevious;
+	static uint32 TimeOfLastChange;
+	uint32 Time;
+	bool DontBind = false;
+
+	FOV = DefaultFOV;	// missing in game
+
+	if(ResetStatics){
+		Rotating = false;
+		DeadZoneReachedOnePrevious = 0.0f;
+		FixedTargetOrientation = 0.0f;
+		ResetStatics = false;
+	}
+
+	CVector TargetCoors = CameraTarget;
+
+	CVector Dist = Source - TargetCoors;
+	Source.z = TargetCoors.z + 0.75f;
+	float Length = Dist.Magnitude2D();
+	if(Length > 2.5f){
+		Source.x = TargetCoors.x + Dist.x/Length * 2.5f;
+		Source.y = TargetCoors.y + Dist.y/Length * 2.5f;
+	}else if(Length < 2.4f){
+		Source.x = TargetCoors.x + Dist.x/Length * 2.4f;
+		Source.y = TargetCoors.y + Dist.y/Length * 2.4f;
+	}
+
+	Beta = CGeneral::GetATanOfXY(Dist.x, Dist.y);
+
+	float StickX = CPad::GetPad(0)->GetLeftStickX();
+	float StickY = CPad::GetPad(0)->GetLeftStickY();
+	float StickAngle;
+	if(StickX != 0.0 || StickY != 0.0f){
+		StickAngle = CGeneral::GetATanOfXY(StickX, StickY);
+		while(StickAngle >= PI) StickAngle -= 2*PI;
+		while(StickAngle < -PI) StickAngle += 2*PI;
+	}else
+		StickAngle = 1000.0f;
+
+	if(Abs(StickAngle-AngleToBinned) > DEGTORAD(15.0f)){
+		DontBind = true;
+		Time = CTimer::GetTimeInMilliseconds();
+	}
+
+	if(CTimer::GetTimeInMilliseconds()-TimeOfLastChange > 200){
+		if(Abs(HALFPI-StickAngle) > DEGTORAD(50.0f)){
+			FixedTargetOrientation = TargetOrientation;
+			Rotating = true;
+			TimeOfLastChange = CTimer::GetTimeInMilliseconds();
+		}
+	}
+
+	if(CPad::GetPad(0)->GetLeftShoulder1JustDown()){
+		FixedTargetOrientation = TargetOrientation;
+		Rotating = true;
+		TimeOfLastChange = CTimer::GetTimeInMilliseconds();
+	}
+
+	// These two together don't make much sense.
+	// Only prevents rotation for one frame
+	AngleToBinned = StickAngle;
+	if(DontBind)
+		TimeOfLastChange = Time;
+
+	if(Rotating){
+		Dist = Source - TargetCoors;
+		Length = Dist.Magnitude2D();
+		// inlined
+		WellBufferMe(FixedTargetOrientation+PI, &Beta, &BetaSpeed, 0.1f, 0.06f, true);
+
+		Source.x = TargetCoors.x + Length*Cos(Beta);
+		Source.y = TargetCoors.y + Length*Sin(Beta);
+
+		float DeltaBeta = FixedTargetOrientation+PI - Beta;
+		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
+		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
+		if(Abs(DeltaBeta) < 0.06f)
+			Rotating = false;
+	}
+
+	Front = TargetCoors - Source;
+	Front.Normalise();
+	CVector Front2 = Front;
+	Front2.Normalise();	// What?
+	// FIX: the meaning of this value must have changed somehow
+	Source -= Front2 * TheCamera.m_fPedZoomValueSmooth*1.5f;
+//	Source += Front2 * TheCamera.m_fPedZoomValueSmooth;
+
+	GetVectorsReadyForRW();
+}
+
+STARTPATCHES
+	InjectHook(0x456F40, WellBufferMe, PATCH_JUMP);
+	InjectHook(0x458410, &CCam::Init, PATCH_JUMP);
+	InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP);
+	InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP);
+	InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP);
+	InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP);
+	InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP);
+	InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP);
+	InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP);
+	InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP);
+	InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP);
+	InjectHook(0x458600, &CCam::LookBehind, PATCH_JUMP);
+	InjectHook(0x458C40, &CCam::LookLeft, PATCH_JUMP);
+	InjectHook(0x458FB0, &CCam::LookRight, PATCH_JUMP);
+	InjectHook(0x4574C0, &CCam::ClipIfPedInFrontOfPlayer, PATCH_JUMP);
+	InjectHook(0x459300, &CCam::KeepTrackOfTheSpeed, PATCH_JUMP);
+	InjectHook(0x458580, &CCam::IsTargetInWater, PATCH_JUMP);
+	InjectHook(0x4570C0, &CCam::AvoidWallsTopDownPed, PATCH_JUMP);
+	InjectHook(0x4595B0, &CCam::PrintMode, PATCH_JUMP);
+
+	InjectHook(0x467400, &CCam::ProcessSpecialHeightRoutines, PATCH_JUMP);
+	InjectHook(0x4596A0, &CCam::Process, PATCH_JUMP);
+	InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP);
+	InjectHook(0x45FF70, &CCam::Process_FollowPedWithMouse, PATCH_JUMP);
+	InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP);
+	InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP);
+	InjectHook(0x463EB0, &CCam::Process_TopDown, PATCH_JUMP);
+	InjectHook(0x464390, &CCam::Process_TopDownPed, PATCH_JUMP);
+	InjectHook(0x461AF0, &CCam::Process_Rocket, PATCH_JUMP);
+	InjectHook(0x460E00, &CCam::Process_M16_1stPerson, PATCH_JUMP);
+	InjectHook(0x459FA0, &CCam::Process_1stPerson, PATCH_JUMP);
+	InjectHook(0x462420, &CCam::Process_Sniper, PATCH_JUMP);
+	InjectHook(0x463130, &CCam::Process_Syphon, PATCH_JUMP);
+	InjectHook(0x463A70, &CCam::Process_Syphon_Crim_In_Front, PATCH_JUMP);
+	InjectHook(0x45B470, &CCam::Process_BehindBoat, PATCH_JUMP);
+	InjectHook(0x45D2F0, &CCam::Process_Fight_Cam, PATCH_JUMP);
+	InjectHook(0x45DC20, &CCam::Process_FlyBy, PATCH_JUMP);
+	InjectHook(0x464D10, &CCam::Process_WheelCam, PATCH_JUMP);
+	InjectHook(0x45DA20, &CCam::Process_Fixed, PATCH_JUMP);
+	InjectHook(0x461940, &CCam::Process_Player_Fallen_Water, PATCH_JUMP);
+	InjectHook(0x45C400, &CCam::Process_Circle, PATCH_JUMP);
+	InjectHook(0x462FC0, &CCam::Process_SpecialFixedForSyphon, PATCH_JUMP);
+	InjectHook(0x45CCC0, &CCam::Process_Debug, PATCH_JUMP);
+	InjectHook(0x4656C0, &CCam::ProcessPedsDeadBaby, PATCH_JUMP);
+	InjectHook(0x465000, &CCam::ProcessArrestCamOne, PATCH_JUMP);
+	InjectHook(0x4653C0, &CCam::ProcessArrestCamTwo, PATCH_JUMP);
+
+	InjectHook(0x456CE0, &FindSplinePathPositionFloat, PATCH_JUMP);
+	InjectHook(0x4569A0, &FindSplinePathPositionVector, PATCH_JUMP);
+
+	InjectHook(0x473250, &CCamera::dtor, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 75e52c5f..3f7ed286 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -13,8 +13,6 @@
 #include "MBlur.h"
 #include "Camera.h"
 
-const float DefaultFOV = 70.0f;	// beta: 80.0f
-
 CCamera &TheCamera = *(CCamera*)0x6FACF8;
 bool &CCamera::m_bUseMouse3rdPerson = *(bool *)0x5F03D8;
 
@@ -38,6 +36,15 @@ CCamera::GetFading()
 	return m_bFading;
 }
 
+int
+CCamera::GetFadingDirection()
+{
+	if(m_bFading)
+		return m_iFadingDirection == FADE_IN ? FADE_IN : FADE_OUT;
+	else
+		return FADE_NONE;
+}
+
 bool
 CCamera::IsSphereVisible(const CVector &center, float radius, const CMatrix *mat)
 {
@@ -182,1148 +189,6 @@ CCamera::ClearPlayerWeaponMode()
 	PlayerWeaponMode.Duration = 0.0f;
 }
 
-
-/*
- *
- * CCam
- *
- */
-
-
-// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms
-// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms
-void
-WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle)
-{
-	float Delta = Target - *CurrentValue;
-
-	if(IsAngle){
-		while(Delta >= PI) Delta -= 2*PI;
-		while(Delta < -PI) Delta += 2*PI;
-	}
-
-	float TargetSpeed = Delta * MaxSpeed;
-	// Add or subtract absolute depending on sign, genius!
-//	if(TargetSpeed - *CurrentSpeed > 0.0f)
-//		*CurrentSpeed += Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
-//	else
-//		*CurrentSpeed -= Acceleration * Abs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
-	// this is simpler:
-	*CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
-
-	// Clamp speed if we overshot
-	if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed)
-		*CurrentSpeed = TargetSpeed;
-	else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed)
-		*CurrentSpeed = TargetSpeed;
-
-	*CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep());
-}
-
-void
-CCam::GetVectorsReadyForRW(void)
-{
-	CVector right;
-	Up = CVector(0.0f, 0.0f, 1.0f);
-	Front.Normalise();
-	if(Front.x == 0.0f && Front.y == 0.0f){
-		Front.x = 0.0001f;
-		Front.y = 0.0001f;
-	}
-	right = CrossProduct(Front, Up);
-	right.Normalise();
-	Up = CrossProduct(right, Front);
-}
-
-// This code is really bad. wtf R*?
-CVector
-CCam::DoAverageOnVector(const CVector &vec)
-{
-	int i;
-	CVector Average = { 0.0f, 0.0f, 0.0f };
-
-	if(ResetStatics){
-		m_iRunningVectorArrayPos = 0;
-		m_iRunningVectorCounter = 1;
-	}
-
-	// TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2
-	if(m_iRunningVectorCounter == 3){
-		m_arrPreviousVectors[0] = m_arrPreviousVectors[1];
-		m_arrPreviousVectors[1] = vec;
-	}else
-		m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec;
-
-	for(i = 0; i <= m_iRunningVectorArrayPos; i++)
-		Average += m_arrPreviousVectors[i];
-	Average /= i;
-
-	m_iRunningVectorArrayPos++;
-	m_iRunningVectorCounter++;
-	if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE)
-		m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1;
-	if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1)
-		m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1;
-
-	return Average;
-}
-
-// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps.
-// Return the first angle for which Beta + BetaOffset + Angle has a clear view.
-// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear.
-// If BetaOffset == 0, try both directions.
-float
-CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
-{
-	CColPoint point;
-	CEntity *ent = nil;
-	CVector ToSource;
-	float a;
-
-	// This would be so much nicer if we just got the step variable before the loop...R*
-
-	for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){
-		if(BetaOffset <= 0.0f){
-			ToSource = CVector(Cos(Beta + BetaOffset + a), Sin(Beta + BetaOffset + a), 0.0f)*Dist;
-			if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
-						point, ent, checkBuildings, checkVehicles, checkPeds,
-						checkObjects, checkDummies, true, true))
-				return a;
-		}
-		if(BetaOffset >= 0.0f){
-			ToSource = CVector(Cos(Beta + BetaOffset - a), Sin(Beta + BetaOffset - a), 0.0f)*Dist;
-			if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
-						point, ent, checkBuildings, checkVehicles, checkPeds,
-						checkObjects, checkDummies, true, true))
-				return -a;
-		}
-	}
-	return 0.0f;
-}
-
-static float DefaultAcceleration = 0.045f;
-static float DefaultMaxStep = 0.15f;
-
-void
-CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float)
-{
-	const float GroundDist = 1.85f;
-
-	CVector TargetCoors, Dist, IdealSource;
-	float Length = 0.0f;
-	float LateralLeft = 0.0f;
-	float LateralRight = 0.0f;
-	float Center = 0.0f;
-	static bool PreviouslyObscured;
-	static bool PickedASide;
-	static float FixedTargetOrientation = 0.0f;
-	float AngleToGoTo = 0.0f;
-	float BetaOffsetAvoidBuildings = 0.45f;		// ~25 deg
-	float BetaOffsetGoingBehind = 0.45f;
-	bool GoingBehind = false;
-	bool Obscured = false;
-	bool BuildingCheckObscured = false;
-	bool HackPlayerOnStoppingTrain = false;
-	static int TimeIndicatedWantedToGoDown = 0;
-	static bool StartedCountingForGoDown = false;
-	float DeltaBeta;
-
-	m_bFixingBeta = false;
-	bBelowMinDist = false;
-	bBehindPlayerDesired = false;
-
-	assert(CamTargetEntity->IsPed());
-
-	// CenterDist should be > LateralDist because we don't have an angle for safety in this case
-	float CenterDist, LateralDist;
-	float AngleToGoToSpeed;
-	if(m_fCloseInPedHeightOffsetSpeed > 0.00001f){
-		LateralDist = 0.55f;
-		CenterDist = 1.25f;
-		BetaOffsetAvoidBuildings = 0.9f;	// ~50 deg
-		BetaOffsetGoingBehind = 0.9f;
-		AngleToGoToSpeed = 0.88254666f;
-	}else{
-		LateralDist = 0.8f;
-		CenterDist = 1.35f;
-		if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){
-			LateralDist = 1.25f;
-			CenterDist = 1.6f;
-		}
-		AngleToGoToSpeed = 0.43254671f;
-	}
-
-	FOV = DefaultFOV;
-
-	if(ResetStatics){
-		Rotating = false;
-		m_bCollisionChecksOn = true;
-		FixedTargetOrientation = 0.0f;
-		PreviouslyObscured = false;
-		PickedASide = false;
-		StartedCountingForGoDown = false;
-		AngleToGoTo = 0.0f;
-		// unused LastAngleWithNoPickedASide
-	}
-
-
-	TargetCoors = CameraTarget;
-	IdealSource = Source;
-	TargetCoors.z += m_fSyphonModeTargetZOffSet;
-
-	CVector TempTargetCoors;
-	TempTargetCoors = DoAverageOnVector(TargetCoors);
-	TargetCoors = TempTargetCoors;
-	// Add this unknown offset, but later it's removed again
-	TargetCoors.z += m_fUnknownZOffSet;
-
-	Dist.x = IdealSource.x - TargetCoors.x;
-	Dist.y = IdealSource.y - TargetCoors.y;
-	Length = Dist.Magnitude2D();
-
-	// Cam on a string. With a fixed distance. Zoom in/out is done later.
-	if(Length != 0.0f)
-		IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist;
-	else
-		IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f);
-
-	// TODO: what's transition beta?
-	if(TheCamera.m_bUseTransitionBeta && ResetStatics){
-		CVector VecDistance;
-		IdealSource.x = TargetCoors.x + GroundDist*Cos(m_fTransitionBeta);
-		IdealSource.y = TargetCoors.y + GroundDist*Sin(m_fTransitionBeta);
-		Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y);
-	}else
-		Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
-
-	if(TheCamera.m_bCamDirectlyBehind){
-		 m_bCollisionChecksOn = true;
-		 Beta = TargetOrientation + PI;
-	}
-
-	if(FindPlayerVehicle())
-		if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN)
-			HackPlayerOnStoppingTrain = true;
-
-	if(TheCamera.m_bCamDirectlyInFront){
-		 m_bCollisionChecksOn = true;
-		 Beta = TargetOrientation;
-	}
-
-	while(Beta >= PI) Beta -= 2.0f * PI;
-	while(Beta < -PI) Beta += 2.0f * PI;
-
-	// BUG? is this ever used?
-	// The values seem to be roughly m_fPedZoomValueSmooth + 1.85
-	if(ResetStatics){
-		if(TheCamera.PedZoomIndicator == 1.0f) m_fRealGroundDist = 2.090556f;
-		if(TheCamera.PedZoomIndicator == 2.0f) m_fRealGroundDist = 3.34973f;
-		if(TheCamera.PedZoomIndicator == 3.0f) m_fRealGroundDist = 4.704914f;
-		if(TheCamera.PedZoomIndicator == 4.0f) m_fRealGroundDist = 2.090556f;
-	}
-	// And what is this? It's only used for collision and rotation it seems
-	float RealGroundDist;
-	if(TheCamera.PedZoomIndicator == 1.0f) RealGroundDist = 2.090556f;
-	if(TheCamera.PedZoomIndicator == 2.0f) RealGroundDist = 3.34973f;
-	if(TheCamera.PedZoomIndicator == 3.0f) RealGroundDist = 4.704914f;
-	if(TheCamera.PedZoomIndicator == 4.0f) RealGroundDist = 2.090556f;
-	if(m_fCloseInPedHeightOffset >  0.00001f)
-		RealGroundDist = 1.7016f;
-
-
-	bool Shooting = false;
-	CPed *ped = (CPed*)CamTargetEntity;
-	if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
-		if(CPad::GetPad(0)->GetWeapon())
-			Shooting = true;
-	if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR ||
-	   ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT)
-		Shooting = false;
-
-
-	if(m_fCloseInPedHeightOffset > 0.00001f)
-		TargetCoors.z -= m_fUnknownZOffSet;
-
-	// Figure out if and where we want to rotate
-
-	if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
-
-		// Center cam behind player
-
-		GoingBehind = true;
-		m_bCollisionChecksOn = true;
-		float OriginalBeta = Beta;
-		// Set Beta behind player
-		Beta = TargetOrientation + PI;
-		TargetCoors.z -= 0.1f;
-
-		AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
-		if(AngleToGoTo != 0.0f){
-			if(AngleToGoTo < 0.0f)
-				AngleToGoTo -= AngleToGoToSpeed;
-			else
-				AngleToGoTo += AngleToGoToSpeed;
-		}else{
-			float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false);
-			float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false);
-			if(LateralLeft == 0.0f && LateralRight != 0.0f)
-				AngleToGoTo += LateralRight;
-			else if(LateralLeft != 0.0f && LateralRight == 0.0f)
-				AngleToGoTo += LateralLeft;
-		}
-
-		TargetCoors.z += 0.1f;
-		Beta = OriginalBeta;
-
-		if(PickedASide){
-			if(AngleToGoTo == 0.0f)
-				FixedTargetOrientation = TargetOrientation + PI;
-			Rotating = true;
-		}else{
-			FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo;
-			Rotating = true;
-			PickedASide = true;
-		}
-	}else{
-
-		// Rotate cam to avoid clipping into buildings
-
-		TargetCoors.z -= 0.1f;
-
-		Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
-		if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){
-			if(Center != 0.0f){
-				AngleToGoTo = Center;
-			}else{
-				LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false);
-				LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false);
-				if(LateralLeft == 0.0f && LateralRight != 0.0f){
-					AngleToGoTo += LateralRight;
-					if(m_fCloseInPedHeightOffset > 0.0f)
-						RwCameraSetNearClipPlane(Scene.camera, 0.7f);
-				}else if(LateralLeft != 0.0f && LateralRight == 0.0f){
-					AngleToGoTo += LateralLeft;
-					if(m_fCloseInPedHeightOffset > 0.0f)
-						RwCameraSetNearClipPlane(Scene.camera, 0.7f);
-				}
-			}
-			if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f)
-				BuildingCheckObscured = true;
-		}
-
-		TargetCoors.z += 0.1f;
-	}
-
-	if(m_fCloseInPedHeightOffset > 0.00001f)
-		TargetCoors.z += m_fUnknownZOffSet;
-
-
-	// Have to fix to avoid collision
-
-	if(AngleToGoTo != 0.0f){
-		Obscured = true;
-		Rotating = true;
-		if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
-			if(!PickedASide)
-				FixedTargetOrientation = Beta + AngleToGoTo;	// can this even happen?
-		}else
-			FixedTargetOrientation = Beta + AngleToGoTo;
-
-		// This calculation is only really used to figure out how fast to rotate out of collision
-
-		m_fAmountFractionObscured = 1.0f;
-		CVector PlayerPos = FindPlayerPed()->GetPosition();
-		float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist;
-		// What's going on here? - AngleToGoTo?
-		CVector RotatedSource = PlayerPos + CVector(Cos(Beta - AngleToGoTo), Sin(Beta - AngleToGoTo), 0.0f) * RotationDist;
-
-		CColPoint colpoint;
-		CEntity *entity;
-		if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){
-			if((PlayerPos - RotatedSource).Magnitude() != 0.0f)
-				m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude();
-			else
-				m_fAmountFractionObscured = 1.0f;
-		}
-	}
-	if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f;
-	if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f;
-
-
-
-	// Figure out speed values for Beta rotation
-
-	float Acceleration, MaxSpeed;
-	static float AccelerationMult = 0.35f;
-	static float MaxSpeedMult = 0.85f;
-	static float AccelerationMultClose = 0.7f;
-	static float MaxSpeedMultClose = 1.6f;
-	float BaseAcceleration = 0.025f;
-	float BaseMaxSpeed = 0.09f;
-	if(m_fCloseInPedHeightOffset > 0.00001f){
-		if(AngleToGoTo == 0.0f){
-			BaseAcceleration = 0.022f;
-			BaseMaxSpeed = 0.04f;
-		}else{
-			BaseAcceleration = DefaultAcceleration;
-			BaseMaxSpeed = DefaultMaxStep;
-		}
-	}
-	if(AngleToGoTo == 0.0f){
-		Acceleration = BaseAcceleration;
-		MaxSpeed = BaseMaxSpeed;
-	}else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){
-		Acceleration = 0.051f;
-		MaxSpeed = 0.18f;
-	}else if(m_fCloseInPedHeightOffset > 0.00001f){
-		Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f);
-		MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f);
-	}else{
-		Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f);
-		MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f);
-	}
-	static float AccelerationLimit = 0.3f;
-	static float MaxSpeedLimit = 0.65f;
-	if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit;
-	if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit;
-
-
-	int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState;
-	if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL &&
-	   !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){
-		Rotating = false;
-		BetaSpeed = 0.0f;
-	}
-
-	// Now do the Beta rotation
-
-	float Distance = (IdealSource - TargetCoors).Magnitude2D();
-	m_fDistanceBeforeChanges = Distance;
-
-	if(Rotating){
-		m_bFixingBeta = true;
-
-		while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI;
-		while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI;
-
-		while(Beta >= PI) Beta -= 2*PI;
-		while(Beta < -PI) Beta += 2*PI;
-
-
-/*
-		// This is inlined WellBufferMe
-		DeltaBeta = FixedTargetOrientation - Beta;
-		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
-		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
-
-		float ReqSpeed = DeltaBeta * MaxSpeed;
-		// Add or subtract absolute depending on sign, genius!
-		if(ReqSpeed - BetaSpeed > 0.0f)
-			BetaSpeed += SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
-		else
-			BetaSpeed -= SpeedStep * Abs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
-		// this would be simpler:
-		// BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep;
-
-		if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed)
-			BetaSpeed = ReqSpeed;
-		else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed)
-			BetaSpeed = ReqSpeed;
-
-		Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep());
-*/
-		WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true);
-
-		if(ResetStatics){
-			Beta = FixedTargetOrientation;
-			BetaSpeed = 0.0f;
-		}
-
-		Source.x = TargetCoors.x + Distance * Cos(Beta);
-		Source.y = TargetCoors.y + Distance * Sin(Beta);
-
-		// Check if we can stop rotating
-		DeltaBeta = FixedTargetOrientation - Beta;
-		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
-		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
-		if(Abs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){
-			// Stop rotation
-			PickedASide = false;
-			Rotating = false;
-			BetaSpeed = 0.0f;
-		}
-	}
-
-
-	if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront ||
-	   HackPlayerOnStoppingTrain || Rotating){
-		if(TheCamera.m_bCamDirectlyBehind){
-			Beta = TargetOrientation + PI;
-			Source.x = TargetCoors.x + Distance * Cos(Beta);
-			Source.y = TargetCoors.y + Distance * Sin(Beta);
-		}
-		if(TheCamera.m_bCamDirectlyInFront){
-			Beta = TargetOrientation;
-			Source.x = TargetCoors.x + Distance * Cos(Beta);
-			Source.y = TargetCoors.y + Distance * Sin(Beta);
-		}
-		if(HackPlayerOnStoppingTrain){
-			Beta = TargetOrientation + PI;
-			Source.x = TargetCoors.x + Distance * Cos(Beta);
-			Source.y = TargetCoors.y + Distance * Sin(Beta);
-			m_fDimensionOfHighestNearCar = 0.0f;
-			m_fCamBufferedHeight = 0.0f;
-			m_fCamBufferedHeightSpeed = 0.0f;
-		}
-		// Beta and Source already set in the rotation code
-	}else{
-		Source = IdealSource;
-		BetaSpeed = 0.0f;
-	}
-
-	// Subtract m_fUnknownZOffSet from both?
-	TargetCoors.z -= m_fUnknownZOffSet;
-	Source.z = IdealSource.z - m_fUnknownZOffSet;
-
-	// Apply zoom now
-	// m_fPedZoomValueSmooth makes the cam go down the further out it is
-	//  0.25 ->  0.20 for nearest dist
-	//  1.50 -> -0.05 for mid dist
-	//  2.90 -> -0.33 for far dist
-	Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f;
-	// Zoom out camera
-	Front = TargetCoors - Source;
-	Front.Normalise();
-	Source -= Front * TheCamera.m_fPedZoomValueSmooth;
-	// and then we move up again
-	//  -0.375
-	//   0.25
-	//   0.95
-	Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset;
-
-
-	// Process height offset to avoid peds and cars
-
-	float TargetZOffSet = m_fUnknownZOffSet + m_fDimensionOfHighestNearCar;
-	TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset);
-	float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z;
-
-	if(TargetHeight > m_fCamBufferedHeight){
-		// Have to go up
-		if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight)
-			WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false);
-		else if(TargetZOffSet == m_fUnknownZOffSet && TargetZOffSet > m_fCamBufferedHeight){
-			// TODO: figure this out
-			bool foo = false;
-			switch(((CPhysical*)CamTargetEntity)->m_nSurfaceTouched)
-			case SURFACE_GRASS:
-			case SURFACE_DIRT:
-			case SURFACE_PAVEMENT:
-			case SURFACE_STEEL:
-			case SURFACE_TIRE:
-			case SURFACE_STONE:
-				foo = true;
-			if(foo)
-				WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false);
-			else
-				WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
-		}else
-			WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
-		StartedCountingForGoDown = false;
-	}else{
-		// Have to go down
-		if(StartedCountingForGoDown){
-			if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){
-				if(TargetHeight > 0.0f)
-					WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
-				else
-					WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
-			}
-		}else{
-			StartedCountingForGoDown = true;
-			TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds();
-		}
-	}
-
-	Source.z += m_fCamBufferedHeight;
-
-
-	// Clip Source if necessary
-
-	bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f;
-	if(GoingBehind || ResetStatics || ClipSource){
-		CColPoint colpoint;
-		CEntity *entity;
-		if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){
-			Source = colpoint.point;
-			if((TargetCoors - Source).Magnitude2D() < 1.0f)
-				RwCameraSetNearClipPlane(Scene.camera, 0.05f);
-		}
-	}
-
-	TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f);
-	m_cvecTargetCoorsForFudgeInter = TargetCoors;
-
-	Front = TargetCoors - Source;
-	m_fRealGroundDist = Front.Magnitude2D();
-	m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist;	
-	Front.Normalise();
-	GetVectorsReadyForRW();
-	TheCamera.m_bCamDirectlyBehind = false;
-	TheCamera.m_bCamDirectlyInFront = false;
-	PreviouslyObscured = BuildingCheckObscured;
-
-	ResetStatics = false;
-}
-
-void
-CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float)
-{
-	FOV = DefaultFOV;
-
-	if(!CamTargetEntity->IsVehicle())
-		return;
-
-	CVector TargetCoors = CameraTarget;
-	TargetCoors.z -= 0.2f;
-	CA_MAX_DISTANCE = 9.95f;
-	CA_MIN_DISTANCE = 8.5f;
-
-	CVector Dist = Source - TargetCoors;
-	float Length = Dist.Magnitude2D();
-	m_fDistanceBeforeChanges = Length;
-	if(Length < 0.002f)
-		Length = 0.002f;
-	Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
-	if(Length > CA_MAX_DISTANCE){
-		Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
-		Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
-	}else if(Length < CA_MIN_DISTANCE){
-		Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
-		Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
-	}
-	TargetCoors.z += 0.8f;
-
-	WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation);
-	RotCamIfInFrontCar(TargetCoors, TargetOrientation);
-	FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation);
-
-	Front = TargetCoors - Source;
-	m_cvecTargetCoorsForFudgeInter = TargetCoors;
-	ResetStatics = false;
-	GetVectorsReadyForRW();
-}
-
-void
-CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation)
-{
-	CColPoint colpoint;
-	CEntity *ent;
-	float TargetZOffSet = 0.0f;
-	static bool PreviouslyFailedRoadHeightCheck = false;
-	static float RoadHeightFix = 0.0f;
-	static float RoadHeightFixSpeed = 0.0f;
-
-	if(ResetStatics){
-		RoadHeightFix = 0.0f;
-		RoadHeightFixSpeed = 0.0f;
-		Alpha = DEGTORAD(25.0f);
-		AlphaSpeed = 0.0f;
-	}
-	float AlphaTarget = DEGTORAD(25.0f);
-	if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
-		AlphaTarget = DEGTORAD(14.0f);
-	WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true);
-	Source.z = TargetCoors.z + CA_MAX_DISTANCE*Sin(Alpha);
-
-	if(FindPlayerVehicle()){
-		m_fUnknownZOffSet = 0.0f;
-		bool FoundRoad = false;
-		bool FoundRoof = false;
-		float RoadZ = 0.0f;
-		float RoofZ = 0.0f;
-
-		if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
-		   ent->IsBuilding()){
-			FoundRoad = true;
-			RoadZ = colpoint.point.z;
-		}
-
-		if(FoundRoad){
-			if(Source.z - RoadZ < 0.9f){
-				PreviouslyFailedRoadHeightCheck = true;
-				TargetZOffSet = RoadZ + 0.9f - Source.z;
-			}else{
-				if(m_bCollisionChecksOn)
-					PreviouslyFailedRoadHeightCheck = false;
-				else
-					TargetZOffSet = 0.0f;
-			}
-		}else{
-			if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) &&
-			   ent->IsBuilding()){
-				FoundRoof = true;
-				RoofZ = colpoint.point.z;
-			}
-			if(FoundRoof){
-				if(Source.z - RoofZ < 0.9f){
-					PreviouslyFailedRoadHeightCheck = true;
-					TargetZOffSet = RoofZ + 0.9f - Source.z;
-				}else{
-					if(m_bCollisionChecksOn)
-						PreviouslyFailedRoadHeightCheck = false;
-					else
-						TargetZOffSet = 0.0f;
-				}
-			}
-		}
-	}
-
-	if(TargetZOffSet > RoadHeightFix)
-		RoadHeightFix = TargetZOffSet;
-	else
-		WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false);
-
-	if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) &&
-	   colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE &&
-	   RoadHeightFix > 1.4f)
-		RoadHeightFix = 1.4f;
-
-	Source.z += RoadHeightFix;
-}
-
-void
-CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight)
-{
-	static float LastTargetAlphaWithCollisionOn = 0.0f;
-	static float LastTopAlphaSpeed = 0.0f;
-	static float LastAlphaSpeedStep = 0.0f;
-	static bool PreviousNearCheckNearClipSmall = false;
-
-	bool CamClear = true;
-	float ModeAlpha = 0.0f;
-
-	if(ResetStatics){
-		LastTargetAlphaWithCollisionOn = 0.0f;
-		LastTopAlphaSpeed = 0.0f;
-		LastAlphaSpeedStep = 0.0f;
-		PreviousNearCheckNearClipSmall = false;
-	}
-
-	float TopAlphaSpeed = 0.15f;
-	float AlphaSpeedStep = 0.015f;
-
-	float zoomvalue = TheCamera.CarZoomValueSmooth;
-	if(zoomvalue < 0.1f)
-		zoomvalue = 0.1f;
-	if(TheCamera.CarZoomIndicator == 1.0f)
-		ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue);	// near
-	else if(TheCamera.CarZoomIndicator == 2.0f)
-		ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue);	// mid
-	else if(TheCamera.CarZoomIndicator == 3.0f)
-		ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue);	// far
-
-
-	float Length = (Source - TargetCoors).Magnitude2D();
-	if(m_bCollisionChecksOn){	// there's another variable (on PC) but it's uninitialised
-		CVector Forward = CamTargetEntity->GetForward();
-		float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z);
-		// this shouldn't be necessary....
-		while(CarAlpha >= PI) CarAlpha -= 2*PI;
-		while(CarAlpha < -PI) CarAlpha += 2*PI;
-
-		while(Beta >= PI) Beta -= 2*PI;
-		while(Beta < -PI) Beta += 2*PI;
-
-		float deltaBeta = Beta - TargetOrientation;
-		while(deltaBeta >= PI) deltaBeta -= 2*PI;
-		while(deltaBeta < -PI) deltaBeta += 2*PI;
-
-		float BehindCarNess = Cos(deltaBeta);	// 1 if behind car, 0 if side, -1 if in front
-		CarAlpha = -CarAlpha * BehindCarNess;
-		if(CarAlpha < -0.01f)
-			CarAlpha = -0.01f;
-
-		float DeltaAlpha = CarAlpha - Alpha;
-		while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
-		while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
-		// What's this?? wouldn't it make more sense to clamp?
-		float AngleLimit = DEGTORAD(1.8f);
-		if(DeltaAlpha < -AngleLimit)
-			DeltaAlpha += AngleLimit;
-		else if(DeltaAlpha > AngleLimit)
-			DeltaAlpha -= AngleLimit;
-		else
-			DeltaAlpha = 0.0f;
-
-		// Now the collision
-
-		float TargetAlpha = 0.0f;
-		bool FoundRoofCenter = false;
-		bool FoundRoofSide1 = false;
-		bool FoundRoofSide2 = false;
-		bool FoundCamRoof = false;
-		bool FoundCamGround = false;
-		float CamRoof = 0.0f;
-		float CarBottom = TargetCoors.z - TargetHeight/2.0f;
-
-		// Check car center
-		float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter);
-
-		// Check sides of the car
-		Forward = CamTargetEntity->GetForward();	// we actually still have that...
-		Forward.Normalise();	// shouldn't be necessary
-		float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f;
-		float SideX = 2.5f * Cos(CarSideAngle);
-		float SideY = 2.5f * Sin(CarSideAngle);
-		CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1);
-		CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2);
-
-		// Now find out at what height we'd like to place the camera
-		float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*Sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround);
-		float CamTargetZ = 0.0f;
-		if(FoundCamGround){
-			// This is the normal case
-			CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof);
-			CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f;
-		}else{
-			FoundCamRoof = false;
-			CamTargetZ = TargetCoors.z;
-		}
-
-		if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){
-			// Car is under something but camera isn't
-			// This seems weird...
-			TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f);
-			CamClear = false;
-		}
-		if(FoundCamRoof){
-			// Camera is under something
-			float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof;
-			// Same weirdness again?
-			TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f);
-			CamClear = false;
-		}
-		while(TargetAlpha >= PI) TargetAlpha -= 2*PI;
-		while(TargetAlpha < -PI) TargetAlpha += 2*PI;
-		if(TargetAlpha < DEGTORAD(-7.0f))
-			TargetAlpha = DEGTORAD(-7.0f);
-
-		// huh?
-		if(TargetAlpha > ModeAlpha)
-			CamClear = true;
-		// Camera is contrained by collision in some way
-		PreviousNearCheckNearClipSmall = false;
-		if(!CamClear){
-			PreviousNearCheckNearClipSmall = true;
-			RwCameraSetNearClipPlane(Scene.camera, 0.9f);
-
-			DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha);
-			while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
-			while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
-
-			TopAlphaSpeed = 0.3f;
-			AlphaSpeedStep = 0.03f;
-		}
-
-		// Now do things if CamClear...but what is that anyway?
-		float CamZ = TargetCoors.z + Length*Sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset;
-		bool FoundGround, FoundRoof;
-		float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround);
-		if(FoundGround){
-			if(CamClear)
-				if(CamZ - CamGround2 < 1.5f){
-					PreviousNearCheckNearClipSmall = true;
-					RwCameraSetNearClipPlane(Scene.camera, 0.9f);
-
-					float a;
-					if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f)
-						a = Alpha;
-					else
-						a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z);
-					while(a > PI) a -= 2*PI;
-					while(a < -PI) a += 2*PI;
-					DeltaAlpha = a - Alpha;
-				}
-		}else{
-			if(CamClear){
-				float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof);
-				if(FoundRoof && CamZ - CamRoof2 < 1.5f){
-					PreviousNearCheckNearClipSmall = true;
-					RwCameraSetNearClipPlane(Scene.camera, 0.9f);
-
-					if(CamRoof2 > TargetCoors.z + 3.5f)
-						CamRoof2 = TargetCoors.z + 3.5f;
-
-					float a;
-					if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f)
-						a = Alpha;
-					else
-						a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z);
-					while(a > PI) a -= 2*PI;
-					while(a < -PI) a += 2*PI;
-					DeltaAlpha = a - Alpha;
-				}
-			}
-		}
-
-		LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha;
-		LastTopAlphaSpeed = TopAlphaSpeed;
-		LastAlphaSpeedStep = AlphaSpeedStep;
-	}else{
-		if(PreviousNearCheckNearClipSmall)
-			RwCameraSetNearClipPlane(Scene.camera, 0.9f);
-	}
-
-	WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true);
-
-	Source.z = TargetCoors.z + Sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset;
-}
-
-// Rotate cam behind the car when the car is moving forward
-bool
-CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation)
-{
-	bool MovingForward = false;
-	CPhysical *phys = (CPhysical*)CamTargetEntity;
-
-	float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f)));
-	if(ForwardSpeed > 0.02f)
-		MovingForward = true;
-
-	float Dist = (Source - TargetCoors).Magnitude2D();
-
-	float DeltaBeta = TargetOrientation - Beta;
-	while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
-	while(DeltaBeta < -PI) DeltaBeta += 2*PI;
-
-	if(Abs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0)
-		m_bFixingBeta = true;
-
-	CPad *pad = CPad::GetPad(0);
-	if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()))
-		if(DirectionWasLooking != LOOKING_FORWARD)
-			TheCamera.m_bCamDirectlyBehind = true;
-
-	if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront)
-		return false;
-
-	bool SetBeta = false;
-	if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta)
-		if(&TheCamera.Cams[TheCamera.ActiveCam] == this)
-			SetBeta = true;
-
-	if(m_bFixingBeta || SetBeta){
-		WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true);
-
-		if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this)
-			Beta = TargetOrientation;
-		if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this)
-			Beta = TargetOrientation + PI;
-		if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this)
-			Beta = m_fTransitionBeta;
-
-		Source.x = TargetCoors.x - Cos(Beta)*Dist;
-		Source.y = TargetCoors.y - Sin(Beta)*Dist;
-
-		// Check if we're done
-		DeltaBeta = TargetOrientation - Beta;
-		while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
-		while(DeltaBeta < -PI) DeltaBeta += 2*PI;
-		if(Abs(DeltaBeta) < DEGTORAD(2.0f))
-			m_bFixingBeta = false;
-	}
-	TheCamera.m_bCamDirectlyBehind = false;
-	TheCamera.m_bCamDirectlyInFront = false;
-	return true;
-}
-
-// Move the cam to avoid clipping through buildings
-bool
-CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation)
-{
-	CVector Target = TargetCoors;
-	bool UseEntityPos = false;
-	CVector EntityPos;
-	static CColPoint colPoint;
-	static bool LastObscured = false;
-
-	if(Mode == MODE_BEHINDCAR)
-		Target.z += TargetHeight/2.0f;
-	if(Mode == MODE_CAM_ON_A_STRING){
-		UseEntityPos = true;
-		Target.z += TargetHeight/2.0f;
-		EntityPos = CamTargetEntity->GetPosition();
-	}
-
-	CVector TempSource = Source;
-
-	bool Obscured1 = false;
-	bool Obscured2 = false;
-	bool Fix1 = false;
-	float Dist1 = 0.0f;
-	float Dist2 = 0.0f;
-	CEntity *ent;
-	if(m_bCollisionChecksOn || LastObscured){
-		Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
-		if(Obscured1){
-			Dist1 = (Target - colPoint.point).Magnitude2D();
-			Fix1 = true;
-			if(UseEntityPos)
-				Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
-		}else if(m_bFixingBeta){
-			float d = (TempSource - Target).Magnitude();
-			TempSource.x = Target.x - d*Cos(TargetOrientation);
-			TempSource.y = Target.y - d*Sin(TargetOrientation);
-
-			// same check again
-			Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
-			if(Obscured2){
-				Dist2 = (Target - colPoint.point).Magnitude2D();
-				if(UseEntityPos)
-					Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
-			}
-		}
-		LastObscured = Obscured1 || Obscured2;
-	}
-
-	// nothing to do
-	if(!LastObscured)
-		return false;
-
-	if(Fix1){
-		Source.x = Target.x - Cos(Beta)*Dist1;
-		Source.y = Target.y - Sin(Beta)*Dist1;
-		if(Mode == MODE_BEHINDCAR)
-			Source = colPoint.point;
-	}else{
-		WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false);
-		Source.x = Target.x - Cos(Beta)*m_fDistanceBeforeChanges;
-		Source.y = Target.y - Sin(Beta)*m_fDistanceBeforeChanges;
-	}
-
-	if(ResetStatics){
-		m_fDistanceBeforeChanges = (Source - Target).Magnitude2D();
-		DistanceSpeed = 0.0f;
-		Source.x = colPoint.point.x;
-		Source.y = colPoint.point.y;
-	}
-	return true;
-}
-
-void
-CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float)
-{
-	if(!CamTargetEntity->IsVehicle())
-		return;
-
-	FOV = DefaultFOV;
-
-	if(ResetStatics){
-		AlphaSpeed = 0.0f;
-		if(TheCamera.m_bIdleOn)
-			TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds();
-	}
-
-	CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex());
-	CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min;
-	float BaseDist = Dimensions.Magnitude2D();
-
-	CVector TargetCoors = CameraTarget;
-	TargetCoors.z += Dimensions.z - 0.1f;	// final
-	Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
-	while(Alpha >= PI) Alpha -= 2*PI;
-	while(Alpha < -PI) Alpha += 2*PI;
-	while(Beta >= PI) Beta -= 2*PI;
-	while(Beta < -PI) Beta += 2*PI;
-
-	m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D();
-
-	Cam_On_A_String_Unobscured(TargetCoors, BaseDist);
-	WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z);
-	RotCamIfInFrontCar(TargetCoors, TargetOrientation);
-	FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation);
-	FixCamWhenObscuredByVehicle(TargetCoors);
-
-	m_cvecTargetCoorsForFudgeInter = TargetCoors;
-	Front = TargetCoors - Source;
-	Front.Normalise();
-	GetVectorsReadyForRW();
-	ResetStatics = false;
-}
-
-// Basic Cam on a string algorithm
-void
-CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist)
-{
-	CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth;
-	CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f);
-
-	CVector Dist = Source - TargetCoors;
-
-	if(ResetStatics)
-		Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f);
-
-	float Length = Dist.Magnitude2D();
-	if(Length < 0.001f){
-		// This probably shouldn't happen. reset view
-		CVector Forward = CamTargetEntity->GetForward();
-		Forward.z = 0.0f;
-		Forward.Normalise();
-		Source = TargetCoors - Forward*CA_MAX_DISTANCE;
-		Dist = Source - TargetCoors;
-		Length = Dist.Magnitude2D();
-	}
-
-	if(Length > CA_MAX_DISTANCE){
-		Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
-		Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
-	}else if(Length < CA_MIN_DISTANCE){
-		Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
-		Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
-	}
-}
-
-void
-CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors)
-{
-	// BUG? is this never reset
-	static float HeightFixerCarsObscuring = 0.0f;
-	static float HeightFixerCarsObscuringSpeed = 0.0f;
-	CColPoint colPoint;
-	CEntity *entity;
-
-	float HeightTarget = 0.0f;
-	if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){
-		CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex());
-		HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z;
-		if(HeightTarget < 0.0f)
-			HeightTarget = 0.0f;
-	}
-	WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false);
-	Source.z += HeightFixerCarsObscuring;
-}
-
-bool
-CCam::Using3rdPersonMouseCam() 
-{
-	return CCamera::m_bUseMouse3rdPerson &&
-		(Mode == MODE_FOLLOWPED ||
-			TheCamera.m_bPlayerIsInGarage &&
-			FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING &&
-			Mode != MODE_TOPDOWN && this->CamTargetEntity == FindPlayerPed());
-}
-
-bool
-CCam::GetWeaponFirstPersonOn()
-{
-	CEntity *target = this->CamTargetEntity;
-	if (target && target->IsPed())
-		return ((CPed*)target)->GetWeapon()->m_bAddRotOffset;
-	
-	return false;
-}
-
 float
 CCamera::Find3rdPersonQuickAimPitch(void)
 {
@@ -1478,22 +343,4 @@ STARTPATCHES
 	InjectHook(0x46B560, &CCamera::FinishCutscene, PATCH_JUMP);
 	InjectHook(0x46FF30, &CCamera::SetZoomValueFollowPedScript, PATCH_JUMP);
 	InjectHook(0x46FF90, &CCamera::SetZoomValueCamStringScript, PATCH_JUMP);
-
-
-	InjectHook(0x456F40, WellBufferMe, PATCH_JUMP);
-	InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP);
-	InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP);
-	InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP);
-	InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP);
-	InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP);
-	InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP);
-	InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP);
-	InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP);
-	InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP);
-
-	InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP);
-	InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP);
-	InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP);
-
-	InjectHook(0x473250, &CCamera::dtor, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/core/Camera.h b/src/core/Camera.h
index 980af5c1..982620a3 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -5,6 +5,8 @@ class CEntity;
 class CPed;
 class CAutomobile;
 
+extern int16 &DebugCamMode;
+
 #define NUMBER_OF_VECTORS_FOR_AVERAGE 2
 
 struct CCam
@@ -66,17 +68,17 @@ struct CCam
 	bool    m_bTheHeightFixerVehicleIsATrain;
 	bool    LookBehindCamWasInFront;
 	bool    LookingBehind;
-	bool    LookingLeft; // 32
+	bool    LookingLeft;
 	bool    LookingRight;
 	bool    ResetStatics; //for interpolation type stuff to work
 	bool    Rotating;
 
 	int16   Mode;                   // CameraMode
-	uint32  m_uiFinishTime; // 52
+	uint32  m_uiFinishTime;
 
 	int     m_iDoCollisionChecksOnFrameNum; 
 	int     m_iDoCollisionCheckEveryNumOfFrames;
-	int     m_iFrameNumWereAt;  // 64
+	int     m_iFrameNumWereAt;
 	int     m_iRunningVectorArrayPos;
 	int     m_iRunningVectorCounter;
 	int     DirectionWasLooking;
@@ -85,9 +87,9 @@ struct CCam
 	float   f_Roll; //used for adding a slight roll to the camera in the
 	float	f_rollSpeed;
 	float   m_fSyphonModeTargetZOffSet;
-	float	m_fUnknownZOffSet;
+	float	m_fRoadOffSet;
 	float   m_fAmountFractionObscured;
-	float   m_fAlphaSpeedOverOneFrame; // 100
+	float   m_fAlphaSpeedOverOneFrame;
 	float   m_fBetaSpeedOverOneFrame;
 	float   m_fBufferedTargetBeta;
 	float   m_fBufferedTargetOrientation;
@@ -95,7 +97,7 @@ struct CCam
 	float   m_fCamBufferedHeight;
 	float   m_fCamBufferedHeightSpeed;
 	float   m_fCloseInPedHeightOffset;
-	float   m_fCloseInPedHeightOffsetSpeed; // 132
+	float   m_fCloseInPedHeightOffsetSpeed;
 	float   m_fCloseInCarHeightOffset;
 	float   m_fCloseInCarHeightOffsetSpeed;
 	float   m_fDimensionOfHighestNearCar;       
@@ -103,7 +105,7 @@ struct CCam
 	float   m_fFovSpeedOverOneFrame;
 	float   m_fMinDistAwayFromCamWhenInterPolating;
 	float   m_fPedBetweenCameraHeightOffset;
-	float   m_fPlayerInFrontSyphonAngleOffSet; // 164
+	float   m_fPlayerInFrontSyphonAngleOffSet;
 	float   m_fRadiusForDead;
 	float   m_fRealGroundDist; //used for follow ped mode
 	float   m_fTargetBeta;
@@ -111,7 +113,7 @@ struct CCam
   
 	float   m_fTransitionBeta;
 	float   m_fTrueBeta;
-	float   m_fTrueAlpha; // 200
+	float   m_fTrueAlpha;
 	float   m_fInitialPlayerOrientation; //used for first person
 
 	float   Alpha;
@@ -120,34 +122,25 @@ struct CCam
 	float   FOVSpeed;
 	float   Beta;
 	float   BetaSpeed;
-	float   Distance; // 232
+	float   Distance;
 	float   DistanceSpeed;
 	float   CA_MIN_DISTANCE;
 	float   CA_MAX_DISTANCE;
 	float   SpeedVar;
 
-	// ped onfoot zoom distance
-	float m_fTargetZoomGroundOne;
-	float m_fTargetZoomGroundTwo; // 256
-	float m_fTargetZoomGroundThree;
-	// ped onfoot alpha angle offset
-	float m_fTargetZoomOneZExtra;
-	float m_fTargetZoomTwoZExtra;
-	float m_fTargetZoomThreeZExtra;
-    
-	float m_fTargetZoomZCloseIn;
-	float m_fMinRealGroundDist;
-	float m_fTargetCloseInDist;
+	CVector m_cvecSourceSpeedOverOneFrame;
+	CVector m_cvecTargetSpeedOverOneFrame;
+	CVector m_cvecUpOverOneFrame;
 
-	CVector m_cvecTargetCoorsForFudgeInter; // 360
-	CVector m_cvecCamFixedModeVector; // 372
-	CVector m_cvecCamFixedModeSource; // 384
-	CVector m_cvecCamFixedModeUpOffSet; // 396
-	CVector m_vecLastAboveWaterCamPosition; //408  //helper for when the player has gone under the water
-	CVector m_vecBufferedPlayerBodyOffset; // 420
+	CVector m_cvecTargetCoorsForFudgeInter;
+	CVector m_cvecCamFixedModeVector;
+	CVector m_cvecCamFixedModeSource;
+	CVector m_cvecCamFixedModeUpOffSet;
+	CVector m_vecLastAboveWaterCamPosition;  //helper for when the player has gone under the water
+	CVector m_vecBufferedPlayerBodyOffset;
 
 	// The three vectors that determine this camera for this frame
-	CVector Front;  // 432                                              // Direction of looking in
+	CVector Front;                                                  // Direction of looking in
 	CVector Source;                                                 // Coors in world space
 	CVector SourceBeforeLookBehind;
 	CVector Up;                                                     // Just that
@@ -162,6 +155,10 @@ struct CCam
 	bool        m_bFirstPersonRunAboutActive;
 
 
+	CCam(void) { Init(); }
+	void Init(void);
+	void Process(void);
+	void ProcessSpecialHeightRoutines(void);
 	void GetVectorsReadyForRW(void);
 	CVector DoAverageOnVector(const CVector &vec);
 	float GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies);
@@ -171,13 +168,59 @@ struct CCam
 	bool FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation);
 	void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist);
 	void FixCamWhenObscuredByVehicle(const CVector &TargetCoors);
-	bool Using3rdPersonMouseCam();
-	bool GetWeaponFirstPersonOn();
+	void LookBehind(void);
+	void LookLeft(void);
+	void LookRight(void);
+	void ClipIfPedInFrontOfPlayer(void);
+	void KeepTrackOfTheSpeed(const CVector &source, const CVector &target, const CVector &up, const float &alpha, const float &beta, const float &fov);
+	bool Using3rdPersonMouseCam(void);
+	bool GetWeaponFirstPersonOn(void);
+	bool IsTargetInWater(const CVector &CamCoors);
+	void AvoidWallsTopDownPed(const CVector &TargetCoors, const CVector &Offset, float *Adjuster, float *AdjusterSpeed, float yDistLimit);
+	void PrintMode(void);
 
-	void Process_Debug(float *vec, float a, float b, float c);
+	void Process_Debug(const CVector&, float, float, float);
+	void Process_Editor(const CVector&, float, float, float);
+	void Process_ModelView(const CVector &CameraTarget, float, float, float);
 	void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float);
 	void Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float);
 	void Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_TopDown(const CVector &CameraTarget, float TargetOrientation, float SpeedVar, float TargetSpeedVar);
+	void Process_TopDownPed(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_Rocket(const CVector &CameraTarget, float, float, float);
+	void Process_M16_1stPerson(const CVector &CameraTarget, float, float, float);
+	void Process_1stPerson(const CVector &CameraTarget, float, float, float);
+	void Process_1rstPersonPedOnPC(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_Sniper(const CVector &CameraTarget, float, float, float);
+	void Process_Syphon(const CVector &CameraTarget, float, float, float);
+	void Process_Syphon_Crim_In_Front(const CVector &CameraTarget, float, float, float);
+	void Process_BehindBoat(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_Fight_Cam(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_FlyBy(const CVector&, float, float, float);
+	void Process_WheelCam(const CVector&, float, float, float);
+	void Process_Fixed(const CVector &CameraTarget, float, float, float);
+	void Process_Player_Fallen_Water(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_Circle(const CVector &CameraTarget, float, float, float);
+	void Process_SpecialFixedForSyphon(const CVector &CameraTarget, float, float, float);
+	void ProcessPedsDeadBaby(void);
+	bool ProcessArrestCamOne(void);
+	bool ProcessArrestCamTwo(void);
+
+	/* Some of the unused PS2 cams */
+	void Process_Chris_With_Binding_PlusRotation(const CVector &CameraTarget, float, float, float);
+	void Process_ReactionCam(const CVector &CameraTarget, float TargetOrientation, float, float);
+	void Process_FollowPed_WithBinding(const CVector &CameraTarget, float TargetOrientation, float, float);
+	// TODO:
+	// CCam::Process_CushyPillows_Arse
+	// CCam::Process_Look_At_Cars
+	// CCam::Process_CheesyZoom
+	// CCam::Process_Aiming
+	// CCam::Process_Bill	// same as BehindCar due to unused variables
+	// CCam::Process_Im_The_Passenger_Woo_Woo
+	// CCam::Process_Blood_On_The_Tracks
+	// CCam::Process_Cam_Running_Side_Train
+	// CCam::Process_Cam_On_Train_Roof
 };
 static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size");
 static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error");
@@ -223,6 +266,7 @@ enum
 
 	FADE_OUT = 0,
 	FADE_IN,
+	FADE_NONE
 };
 
 enum
@@ -445,8 +489,8 @@ uint32    unknown;
 uint32  m_fScriptTimeForInterPolation;
 
 
-int16   m_iFadingDirection;
-int     m_iModeObbeCamIsInForCar;
+	int16   m_iFadingDirection;
+	int     m_iModeObbeCamIsInForCar;
 	int16   m_iModeToGoTo;
 	int16   m_iMusicFadingDirection;
 	int16   m_iTypeOfSwitch;
@@ -493,6 +537,7 @@ int     m_iModeObbeCamIsInForCar;
 	void TakeControlNoEntity(const CVector&, int16, int32);
 	void SetCamPositionForFixedMode(const CVector&, const CVector&);
 	bool GetFading();
+	int GetFadingDirection();
 
 	void Init();
 	void SetRwCamera(RwCamera*);
@@ -525,8 +570,12 @@ static_assert(offsetof(CCamera, m_uiTransitionState) == 0x89, "CCamera: error");
 static_assert(offsetof(CCamera, m_uiTimeTransitionStart) == 0x94, "CCamera: error");
 static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error");
 static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error");
+static_assert(offsetof(CCamera, pToGarageWeAreIn) == 0x690, "CCamera: error");
+static_assert(offsetof(CCamera, m_PreviousCameraPosition) == 0x6B0, "CCamera: error");
 static_assert(offsetof(CCamera, m_vecCutSceneOffset) == 0x6F8, "CCamera: error");
+static_assert(offsetof(CCamera, m_arrPathArray) == 0x7a8, "CCamera: error");
 static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size");
+
 extern CCamera &TheCamera;
 
-void CamShakeNoPos(CCamera*, float);
\ No newline at end of file
+void CamShakeNoPos(CCamera*, float);
diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp
index 57b1cbe2..a400c039 100644
--- a/src/core/CdStream.cpp
+++ b/src/core/CdStream.cpp
@@ -43,6 +43,7 @@ BOOL _gbCdStreamOverlapped;
 BOOL _gbCdStreamAsync;
 DWORD _gdwCdStreamFlags;
 
+DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter);
 
 void
 CdStreamInitThread(void)
diff --git a/src/core/CdStream.h b/src/core/CdStream.h
index 55507aa8..9ef71b65 100644
--- a/src/core/CdStream.h
+++ b/src/core/CdStream.h
@@ -39,7 +39,6 @@ int32 CdStreamSync(int32 channel);
 void AddToQueue(Queue *queue, int32 item);
 int32 GetFirstInQueue(Queue *queue);
 void RemoveFirstInQueue(Queue *queue);
-DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter);
 bool CdStreamAddImage(char const *path);
 char *CdStreamGetImageName(int32 cd);
 void CdStreamRemoveImages(void);
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index fc8428be..94ef769e 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -2061,6 +2061,19 @@ CColModel::operator=(const CColModel &other)
 	return *this;
 }
 
+#include <new>
+struct CColLine_ : public CColLine
+{
+	CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); }
+};
+
+struct CColModel_ : public CColModel
+{
+	CColModel *ctor(void) { return ::new (this) CColModel(); }
+	void dtor(void) { this->CColModel::~CColModel(); }
+};
+
+
 STARTPATCHES
 	InjectHook(0x4B9C30, (CMatrix& (*)(const CMatrix &src, CMatrix &dst))Invert, PATCH_JUMP);
 
@@ -2099,15 +2112,15 @@ STARTPATCHES
 
 	InjectHook(0x411E40, (void (CColSphere::*)(float, const CVector&, uint8, uint8))&CColSphere::Set, PATCH_JUMP);
 	InjectHook(0x40B2A0, &CColBox::Set, PATCH_JUMP);
-	InjectHook(0x40B320, &CColLine::ctor, PATCH_JUMP);
+	InjectHook(0x40B320, &CColLine_::ctor, PATCH_JUMP);
 	InjectHook(0x40B350, &CColLine::Set, PATCH_JUMP);
 	InjectHook(0x411E70, &CColTriangle::Set, PATCH_JUMP);
 
 	InjectHook(0x411EA0, &CColTrianglePlane::Set, PATCH_JUMP);
 	InjectHook(0x412140, &CColTrianglePlane::GetNormal, PATCH_JUMP);
 
-	InjectHook(0x411680, &CColModel::ctor, PATCH_JUMP);
-	InjectHook(0x4116E0, &CColModel::dtor, PATCH_JUMP);
+	InjectHook(0x411680, &CColModel_::ctor, PATCH_JUMP);
+	InjectHook(0x4116E0, &CColModel_::dtor, PATCH_JUMP);
 	InjectHook(0x411D80, &CColModel::RemoveCollisionVolumes, PATCH_JUMP);
 	InjectHook(0x411CB0, &CColModel::CalculateTrianglePlanes, PATCH_JUMP);
 	InjectHook(0x411D10, &CColModel::RemoveTrianglePlanes, PATCH_JUMP);
diff --git a/src/core/Collision.h b/src/core/Collision.h
index 9597a181..429fc17f 100644
--- a/src/core/Collision.h
+++ b/src/core/Collision.h
@@ -35,8 +35,6 @@ struct CColLine
 	CColLine(void) { };
 	CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; };
 	void Set(const CVector &p0, const CVector &p1);
-
-	CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); }
 };
 
 struct CColTriangle
@@ -106,8 +104,6 @@ struct CColModel
 	void SetLinkPtr(CLink<CColModel*>*);
 	void GetTrianglePoint(CVector &v, int i) const;
 
-	CColModel *ctor(void) { return ::new (this) CColModel(); }
-	void dtor(void) { this->CColModel::~CColModel(); }
 	CColModel& operator=(const CColModel& other);
 };
 
diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp
index 92c51182..541257c6 100644
--- a/src/core/ControllerConfig.cpp
+++ b/src/core/ControllerConfig.cpp
@@ -417,6 +417,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int32 button, i
 			case 13:
 				pad->PCTempJoyState.DPadUp = 255;
 				break;
+#ifdef REGISTER_START_BUTTON
+			case 12:
+				pad->PCTempJoyState.Start = 255;
+				break;
+#endif
 			case 11:
 				pad->PCTempJoyState.RightShock = 255;
 				break;
@@ -839,6 +844,11 @@ void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int32 button, int
 			case 13:
 				pad->PCTempJoyState.DPadUp = 0;
 				break;
+#ifdef REGISTER_START_BUTTON
+			case 12:
+				pad->PCTempJoyState.Start = 0;
+				break;
+#endif
 			case 11:
 				pad->PCTempJoyState.RightShock = 0;
 				break;
diff --git a/src/core/CutsceneMgr.cpp b/src/core/CutsceneMgr.cpp
index 3df81b2b..c13aa3a8 100644
--- a/src/core/CutsceneMgr.cpp
+++ b/src/core/CutsceneMgr.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS	// just for VK_SPACE
 #include "common.h"
 #include "patcher.h"
 #include "General.h"
@@ -27,79 +28,79 @@ const struct {
 	{ "BET",		STREAMED_SOUND_BANK_INTRO },
 	{ "L1_LG",		STREAMED_SOUND_CUTSCENE_LUIGI1_LG },
 	{ "L2_DSB",		STREAMED_SOUND_CUTSCENE_LUIGI2_DSB },
-	{ "L3_DM",		STREAMED_SOUND_CUTSCENE_LUIGI3_DM },
-	{ "L4_PAP",		STREAMED_SOUND_CUTSCENE_LUIGI4_PAP },
-	{ "L5_TFB",		STREAMED_SOUND_CUTSCENE_LUIGI5_TFB },
-	{ "J0_DM2",		STREAMED_SOUND_CUTSCENE_JOEY0_DM2 },
-	{ "J1_LFL",		STREAMED_SOUND_CUTSCENE_JOEY1_LFL },
-	{ "J2_KCL",		STREAMED_SOUND_CUTSCENE_JOEY2_KCL },
-	{ "J3_VH",		STREAMED_SOUND_CUTSCENE_JOEY3_VH },
-	{ "J4_ETH",		STREAMED_SOUND_CUTSCENE_JOEY4_ETH },
-	{ "J5_DST",		STREAMED_SOUND_CUTSCENE_JOEY5_DST },
-	{ "J6_TBJ",		STREAMED_SOUND_CUTSCENE_JOEY6_TBJ },
-	{ "T1_TOL",		STREAMED_SOUND_CUTSCENE_TONI1_TOL },
-	{ "T2_TPU",		STREAMED_SOUND_CUTSCENE_TONI2_TPU },
-	{ "T3_MAS",		STREAMED_SOUND_CUTSCENE_TONI3_MAS },
-	{ "T4_TAT",		STREAMED_SOUND_CUTSCENE_TONI4_TAT },
-	{ "T5_BF",		STREAMED_SOUND_CUTSCENE_TONI5_BF },
-	{ "S0_MAS",		STREAMED_SOUND_CUTSCENE_SAL0_MAS },
-	{ "S1_PF",		STREAMED_SOUND_CUTSCENE_SAL1_PF },
-	{ "S2_CTG",		STREAMED_SOUND_CUTSCENE_SAL2_CTG },
-	{ "S3_RTC",		STREAMED_SOUND_CUTSCENE_SAL3_RTC },
-	{ "S5_LRQ",		STREAMED_SOUND_CUTSCENE_SAL5_LRQ },
-	{ "S4_BDBA",	STREAMED_SOUND_CUTSCENE_SAL4_BDBA },
-	{ "S4_BDBB",	STREAMED_SOUND_CUTSCENE_SAL4_BDBB },
-	{ "S2_CTG2",	STREAMED_SOUND_CUTSCENE_SAL2_CTG2 },
-	{ "S4_BDBD",	STREAMED_SOUND_CUTSCENE_SAL4_BDBD },
-	{ "S5_LRQB",	STREAMED_SOUND_CUTSCENE_SAL5_LRQB },
-	{ "S5_LRQC",	STREAMED_SOUND_CUTSCENE_SAL5_LRQC },
-	{ "A1_SS0",		STREAMED_SOUND_CUTSCENE_ASUKA_1_SSO },
-	{ "A2_PP",		STREAMED_SOUND_CUTSCENE_ASUKA_2_PP },
-	{ "A3_SS",		STREAMED_SOUND_CUTSCENE_ASUKA_3_SS },
-	{ "A4_PDR",		STREAMED_SOUND_CUTSCENE_ASUKA_4_PDR },
-	{ "A5_K2FT",	STREAMED_SOUND_CUTSCENE_ASUKA_5_K2FT},
-	{ "K1_KBO",		STREAMED_SOUND_CUTSCENE_KENJI1_KBO },
-	{ "K2_GIS",		STREAMED_SOUND_CUTSCENE_KENJI2_GIS },
-	{ "K3_DS",		STREAMED_SOUND_CUTSCENE_KENJI3_DS },
-	{ "K4_SHI",		STREAMED_SOUND_CUTSCENE_KENJI4_SHI },
-	{ "K5_SD",		STREAMED_SOUND_CUTSCENE_KENJI5_SD },
-	{ "R0_PDR2",	STREAMED_SOUND_CUTSCENE_RAY0_PDR2 },
-	{ "R1_SW",		STREAMED_SOUND_CUTSCENE_RAY1_SW },
-	{ "R2_AP",		STREAMED_SOUND_CUTSCENE_RAY2_AP },
-	{ "R3_ED",		STREAMED_SOUND_CUTSCENE_RAY3_ED },
-	{ "R4_GF",		STREAMED_SOUND_CUTSCENE_RAY4_GF },
-	{ "R5_PB",		STREAMED_SOUND_CUTSCENE_RAY5_PB },
-	{ "R6_MM",		STREAMED_SOUND_CUTSCENE_RAY6_MM },
-	{ "D1_STOG",	STREAMED_SOUND_CUTSCENE_DONALD1_STOG },
-	{ "D2_KK",		STREAMED_SOUND_CUTSCENE_DONALD2_KK },
-	{ "D3_ADO",		STREAMED_SOUND_CUTSCENE_DONALD3_ADO },
-	{ "D5_ES",		STREAMED_SOUND_CUTSCENE_DONALD5_ES },
-	{ "D7_MLD",		STREAMED_SOUND_CUTSCENE_DONALD7_MLD },
-	{ "D4_GTA",		STREAMED_SOUND_CUTSCENE_DONALD4_GTA },
-	{ "D4_GTA2",	STREAMED_SOUND_CUTSCENE_DONALD4_GTA2 },
-	{ "D6_STS",		STREAMED_SOUND_CUTSCENE_DONALD6_STS },
-	{ "A6_BAIT",	STREAMED_SOUND_CUTSCENE_ASUKA6_BAIT },
-	{ "A7_ETG",		STREAMED_SOUND_CUTSCENE_ASUKA7_ETG },
-	{ "A8_PS",		STREAMED_SOUND_CUTSCENE_ASUKA8_PS },
-	{ "A9_ASD",		STREAMED_SOUND_CUTSCENE_ASUKA9_ASD },
-	{ "K4_SHI2",	STREAMED_SOUND_CUTSCENE_KENJI4_SHI2 },
-	{ "C1_TEX",		STREAMED_SOUND_CUTSCENE_CATALINA1_TEX },
-	{ "EL_PH1",		STREAMED_SOUND_CUTSCENE_ELBURRO1_PH1 },
-	{ "EL_PH2",		STREAMED_SOUND_CUTSCENE_ELBURRO2_PH2 },
-	{ "EL_PH3",		STREAMED_SOUND_CUTSCENE_ELBURRO3_PH3 },
-	{ "EL_PH4",		STREAMED_SOUND_CUTSCENE_ELBURRO4_PH4 },
-	{ "YD_PH1",		STREAMED_SOUND_CUTSCENE_YARDIE_PH1 },
-	{ "YD_PH2",		STREAMED_SOUND_CUTSCENE_YARDIE_PH2 },
-	{ "YD_PH3",		STREAMED_SOUND_CUTSCENE_YARDIE_PH3 },
-	{ "YD_PH4",		STREAMED_SOUND_CUTSCENE_YARDIE_PH4 },
-	{ "HD_PH1",		STREAMED_SOUND_CUTSCENE_HOODS_PH1 },
-	{ "HD_PH2",		STREAMED_SOUND_CUTSCENE_HOODS_PH2 },
-	{ "HD_PH3",		STREAMED_SOUND_CUTSCENE_HOODS_PH3 },
-	{ "HD_PH4",		STREAMED_SOUND_CUTSCENE_HOODS_PH4 },
-	{ "HD_PH5",		STREAMED_SOUND_CUTSCENE_HOODS_PH5 },
-	{ "MT_PH1",		STREAMED_SOUND_CUTSCENE_MARTY_PH1 },
-	{ "MT_PH2",		STREAMED_SOUND_CUTSCENE_MARTY_PH2 },
-	{ "MT_PH3",		STREAMED_SOUND_CUTSCENE_MARTY_PH3 },
+	{ "L3_DM",		STREAMED_SOUND_CUTSCENE_LUIGI3_DM },
+	{ "L4_PAP",		STREAMED_SOUND_CUTSCENE_LUIGI4_PAP },
+	{ "L5_TFB",		STREAMED_SOUND_CUTSCENE_LUIGI5_TFB },
+	{ "J0_DM2",		STREAMED_SOUND_CUTSCENE_JOEY0_DM2 },
+	{ "J1_LFL",		STREAMED_SOUND_CUTSCENE_JOEY1_LFL },
+	{ "J2_KCL",		STREAMED_SOUND_CUTSCENE_JOEY2_KCL },
+	{ "J3_VH",		STREAMED_SOUND_CUTSCENE_JOEY3_VH },
+	{ "J4_ETH",		STREAMED_SOUND_CUTSCENE_JOEY4_ETH },
+	{ "J5_DST",		STREAMED_SOUND_CUTSCENE_JOEY5_DST },
+	{ "J6_TBJ",		STREAMED_SOUND_CUTSCENE_JOEY6_TBJ },
+	{ "T1_TOL",		STREAMED_SOUND_CUTSCENE_TONI1_TOL },
+	{ "T2_TPU",		STREAMED_SOUND_CUTSCENE_TONI2_TPU },
+	{ "T3_MAS",		STREAMED_SOUND_CUTSCENE_TONI3_MAS },
+	{ "T4_TAT",		STREAMED_SOUND_CUTSCENE_TONI4_TAT },
+	{ "T5_BF",		STREAMED_SOUND_CUTSCENE_TONI5_BF },
+	{ "S0_MAS",		STREAMED_SOUND_CUTSCENE_SAL0_MAS },
+	{ "S1_PF",		STREAMED_SOUND_CUTSCENE_SAL1_PF },
+	{ "S2_CTG",		STREAMED_SOUND_CUTSCENE_SAL2_CTG },
+	{ "S3_RTC",		STREAMED_SOUND_CUTSCENE_SAL3_RTC },
+	{ "S5_LRQ",		STREAMED_SOUND_CUTSCENE_SAL5_LRQ },
+	{ "S4_BDBA",	STREAMED_SOUND_CUTSCENE_SAL4_BDBA },
+	{ "S4_BDBB",	STREAMED_SOUND_CUTSCENE_SAL4_BDBB },
+	{ "S2_CTG2",	STREAMED_SOUND_CUTSCENE_SAL2_CTG2 },
+	{ "S4_BDBD",	STREAMED_SOUND_CUTSCENE_SAL4_BDBD },
+	{ "S5_LRQB",	STREAMED_SOUND_CUTSCENE_SAL5_LRQB },
+	{ "S5_LRQC",	STREAMED_SOUND_CUTSCENE_SAL5_LRQC },
+	{ "A1_SS0",		STREAMED_SOUND_CUTSCENE_ASUKA_1_SSO },
+	{ "A2_PP",		STREAMED_SOUND_CUTSCENE_ASUKA_2_PP },
+	{ "A3_SS",		STREAMED_SOUND_CUTSCENE_ASUKA_3_SS },
+	{ "A4_PDR",		STREAMED_SOUND_CUTSCENE_ASUKA_4_PDR },
+	{ "A5_K2FT",	STREAMED_SOUND_CUTSCENE_ASUKA_5_K2FT},
+	{ "K1_KBO",		STREAMED_SOUND_CUTSCENE_KENJI1_KBO },
+	{ "K2_GIS",		STREAMED_SOUND_CUTSCENE_KENJI2_GIS },
+	{ "K3_DS",		STREAMED_SOUND_CUTSCENE_KENJI3_DS },
+	{ "K4_SHI",		STREAMED_SOUND_CUTSCENE_KENJI4_SHI },
+	{ "K5_SD",		STREAMED_SOUND_CUTSCENE_KENJI5_SD },
+	{ "R0_PDR2",	STREAMED_SOUND_CUTSCENE_RAY0_PDR2 },
+	{ "R1_SW",		STREAMED_SOUND_CUTSCENE_RAY1_SW },
+	{ "R2_AP",		STREAMED_SOUND_CUTSCENE_RAY2_AP },
+	{ "R3_ED",		STREAMED_SOUND_CUTSCENE_RAY3_ED },
+	{ "R4_GF",		STREAMED_SOUND_CUTSCENE_RAY4_GF },
+	{ "R5_PB",		STREAMED_SOUND_CUTSCENE_RAY5_PB },
+	{ "R6_MM",		STREAMED_SOUND_CUTSCENE_RAY6_MM },
+	{ "D1_STOG",	STREAMED_SOUND_CUTSCENE_DONALD1_STOG },
+	{ "D2_KK",		STREAMED_SOUND_CUTSCENE_DONALD2_KK },
+	{ "D3_ADO",		STREAMED_SOUND_CUTSCENE_DONALD3_ADO },
+	{ "D5_ES",		STREAMED_SOUND_CUTSCENE_DONALD5_ES },
+	{ "D7_MLD",		STREAMED_SOUND_CUTSCENE_DONALD7_MLD },
+	{ "D4_GTA",		STREAMED_SOUND_CUTSCENE_DONALD4_GTA },
+	{ "D4_GTA2",	STREAMED_SOUND_CUTSCENE_DONALD4_GTA2 },
+	{ "D6_STS",		STREAMED_SOUND_CUTSCENE_DONALD6_STS },
+	{ "A6_BAIT",	STREAMED_SOUND_CUTSCENE_ASUKA6_BAIT },
+	{ "A7_ETG",		STREAMED_SOUND_CUTSCENE_ASUKA7_ETG },
+	{ "A8_PS",		STREAMED_SOUND_CUTSCENE_ASUKA8_PS },
+	{ "A9_ASD",		STREAMED_SOUND_CUTSCENE_ASUKA9_ASD },
+	{ "K4_SHI2",	STREAMED_SOUND_CUTSCENE_KENJI4_SHI2 },
+	{ "C1_TEX",		STREAMED_SOUND_CUTSCENE_CATALINA1_TEX },
+	{ "EL_PH1",		STREAMED_SOUND_CUTSCENE_ELBURRO1_PH1 },
+	{ "EL_PH2",		STREAMED_SOUND_CUTSCENE_ELBURRO2_PH2 },
+	{ "EL_PH3",		STREAMED_SOUND_CUTSCENE_ELBURRO3_PH3 },
+	{ "EL_PH4",		STREAMED_SOUND_CUTSCENE_ELBURRO4_PH4 },
+	{ "YD_PH1",		STREAMED_SOUND_CUTSCENE_YARDIE_PH1 },
+	{ "YD_PH2",		STREAMED_SOUND_CUTSCENE_YARDIE_PH2 },
+	{ "YD_PH3",		STREAMED_SOUND_CUTSCENE_YARDIE_PH3 },
+	{ "YD_PH4",		STREAMED_SOUND_CUTSCENE_YARDIE_PH4 },
+	{ "HD_PH1",		STREAMED_SOUND_CUTSCENE_HOODS_PH1 },
+	{ "HD_PH2",		STREAMED_SOUND_CUTSCENE_HOODS_PH2 },
+	{ "HD_PH3",		STREAMED_SOUND_CUTSCENE_HOODS_PH3 },
+	{ "HD_PH4",		STREAMED_SOUND_CUTSCENE_HOODS_PH4 },
+	{ "HD_PH5",		STREAMED_SOUND_CUTSCENE_HOODS_PH5 },
+	{ "MT_PH1",		STREAMED_SOUND_CUTSCENE_MARTY_PH1 },
+	{ "MT_PH2",		STREAMED_SOUND_CUTSCENE_MARTY_PH2 },
+	{ "MT_PH3",		STREAMED_SOUND_CUTSCENE_MARTY_PH3 },
 	{ "MT_PH4",		STREAMED_SOUND_CUTSCENE_MARTY_PH4 },
 	{ NULL,			NULL }
 };
@@ -128,135 +129,135 @@ CVector &CCutsceneMgr::ms_cutsceneOffset = *(CVector*)0x8F2C0C;
 float &CCutsceneMgr::ms_cutsceneTimer = *(float*)0x941548;
 uint32 &CCutsceneMgr::ms_cutsceneLoadStatus = *(uint32*)0x95CB40;
 
-RpAtomic *
-CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data)
-{
-	float radius = RpAtomicGetBoundingSphereMacro(atomic)->radius;
-	RwV3d center = RpAtomicGetBoundingSphereMacro(atomic)->center;
-
-	for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame))
-		RwV3dTransformPoints(&center, &center, 1, RwFrameGetMatrix(frame));
-
-	float size = RwV3dLength(&center) + radius;
-	if (size > *(float *)data)
-		*(float *)data = size;
-	return atomic;
+RpAtomic *
+CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data)
+{
+	float radius = RpAtomicGetBoundingSphereMacro(atomic)->radius;
+	RwV3d center = RpAtomicGetBoundingSphereMacro(atomic)->center;
+
+	for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame))
+		RwV3dTransformPoints(&center, &center, 1, RwFrameGetMatrix(frame));
+
+	float size = RwV3dLength(&center) + radius;
+	if (size > *(float *)data)
+		*(float *)data = size;
+	return atomic;
 }
 
 void
 CCutsceneMgr::Initialise(void)
-{
-	ms_numCutsceneObjs = 0;
-	ms_loaded = false;
-	ms_running = false;
-	ms_animLoaded = false;
-	ms_cutsceneProcessing = false;
-	ms_useLodMultiplier = false;
-
-	ms_pCutsceneDir = new CDirectory(CUTSCENEDIRSIZE);
+{
+	ms_numCutsceneObjs = 0;
+	ms_loaded = false;
+	ms_running = false;
+	ms_animLoaded = false;
+	ms_cutsceneProcessing = false;
+	ms_useLodMultiplier = false;
+
+	ms_pCutsceneDir = new CDirectory(CUTSCENEDIRSIZE);
 	ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
 }
 
-void
-CCutsceneMgr::Shutdown(void)
-{
-	delete ms_pCutsceneDir;
+void
+CCutsceneMgr::Shutdown(void)
+{
+	delete ms_pCutsceneDir;
 }
 
-void
-CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName)
-{
-	int file;
-	uint32 size;
-	uint32 offset;
-	CPlayerPed *pPlayerPed;
-
-	ms_cutsceneProcessing = true;
-	if (!strcasecmp(szCutsceneName, "jb"))
-		ms_useLodMultiplier = true;
-	CTimer::Stop();
-
-	ms_pCutsceneDir->numEntries = 0;
-	ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
-
-	CStreaming::RemoveUnusedModelsInLoadedList();
-	CGame::DrasticTidyUpMemory();
-
-	strcpy(ms_cutsceneName, szCutsceneName);
-	file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
-
-	// Load animations
-	sprintf(gString, "%s.IFP", szCutsceneName);
-	if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
-		CStreaming::MakeSpaceFor(size << 11);
-		CStreaming::ImGonnaUseStreamingMemory();
-		CFileMgr::Seek(file, offset << 11, SEEK_SET);
-		CAnimManager::LoadAnimFile(file, false);
-		ms_cutsceneAssociations.CreateAssociations(szCutsceneName);
-		CStreaming::IHaveUsedStreamingMemory();
-		ms_animLoaded = true;
-	} else {
-		ms_animLoaded = false;
-	}
-
-	// Load camera data
-	sprintf(gString, "%s.DAT", szCutsceneName);
-	if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
-		CFileMgr::Seek(file, offset << 11, SEEK_SET);
-		TheCamera.LoadPathSplines(file);
-	}
-
-	CFileMgr::CloseFile(file);
-
-	if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
-		DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
-		int trackId = FindCutsceneAudioTrackId(szCutsceneName);
-		if (trackId != -1) {
-			printf("Start preload audio %s\n", szCutsceneName);
-			DMAudio.PreloadCutSceneMusic(trackId);
-			printf("End preload audio %s\n", szCutsceneName);
-		}
-	}
-
-	ms_cutsceneTimer = 0.0f;
-	ms_loaded = true;
-	ms_cutsceneOffset = CVector(0.0f, 0.0f, 0.0f);
-
-	pPlayerPed = FindPlayerPed();
-	CTimer::Update();
-
-	pPlayerPed->m_pWanted->ClearQdCrimes();
-	pPlayerPed->bIsVisible = false;
-	pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
-	CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80;
-	CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(true);
+void
+CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName)
+{
+	int file;
+	uint32 size;
+	uint32 offset;
+	CPlayerPed *pPlayerPed;
+
+	ms_cutsceneProcessing = true;
+	if (!strcasecmp(szCutsceneName, "jb"))
+		ms_useLodMultiplier = true;
+	CTimer::Stop();
+
+	ms_pCutsceneDir->numEntries = 0;
+	ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
+
+	CStreaming::RemoveUnusedModelsInLoadedList();
+	CGame::DrasticTidyUpMemory();
+
+	strcpy(ms_cutsceneName, szCutsceneName);
+	file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
+
+	// Load animations
+	sprintf(gString, "%s.IFP", szCutsceneName);
+	if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
+		CStreaming::MakeSpaceFor(size << 11);
+		CStreaming::ImGonnaUseStreamingMemory();
+		CFileMgr::Seek(file, offset << 11, SEEK_SET);
+		CAnimManager::LoadAnimFile(file, false);
+		ms_cutsceneAssociations.CreateAssociations(szCutsceneName);
+		CStreaming::IHaveUsedStreamingMemory();
+		ms_animLoaded = true;
+	} else {
+		ms_animLoaded = false;
+	}
+
+	// Load camera data
+	sprintf(gString, "%s.DAT", szCutsceneName);
+	if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
+		CFileMgr::Seek(file, offset << 11, SEEK_SET);
+		TheCamera.LoadPathSplines(file);
+	}
+
+	CFileMgr::CloseFile(file);
+
+	if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
+		DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
+		int trackId = FindCutsceneAudioTrackId(szCutsceneName);
+		if (trackId != -1) {
+			printf("Start preload audio %s\n", szCutsceneName);
+			DMAudio.PreloadCutSceneMusic(trackId);
+			printf("End preload audio %s\n", szCutsceneName);
+		}
+	}
+
+	ms_cutsceneTimer = 0.0f;
+	ms_loaded = true;
+	ms_cutsceneOffset = CVector(0.0f, 0.0f, 0.0f);
+
+	pPlayerPed = FindPlayerPed();
+	CTimer::Update();
+
+	pPlayerPed->m_pWanted->ClearQdCrimes();
+	pPlayerPed->bIsVisible = false;
+	pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
+	CPad::GetPad(0)->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80;
+	CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(true);
 }
 
-void
-CCutsceneMgr::SetHeadAnim(const char *animName, CObject *pObject)
-{
-	CCutsceneHead *pCutsceneHead = (CCutsceneHead*)pObject;
-	char szAnim[CUTSCENENAMESIZE * 2];
-
-	sprintf(szAnim, "%s_%s", ms_cutsceneName, animName);
-	pCutsceneHead->PlayAnimation(szAnim);
+void
+CCutsceneMgr::SetHeadAnim(const char *animName, CObject *pObject)
+{
+	CCutsceneHead *pCutsceneHead = (CCutsceneHead*)pObject;
+	char szAnim[CUTSCENENAMESIZE * 2];
+
+	sprintf(szAnim, "%s_%s", ms_cutsceneName, animName);
+	pCutsceneHead->PlayAnimation(szAnim);
 }
 
-void
-CCutsceneMgr::FinishCutscene()
-{
-	CCutsceneMgr::ms_cutsceneTimer = TheCamera.GetCutSceneFinishTime() * 0.001f;
-	TheCamera.FinishCutscene();
-
-	FindPlayerPed()->bIsVisible = true;
-	CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
+void
+CCutsceneMgr::FinishCutscene()
+{
+	CCutsceneMgr::ms_cutsceneTimer = TheCamera.GetCutSceneFinishTime() * 0.001f;
+	TheCamera.FinishCutscene();
+
+	FindPlayerPed()->bIsVisible = true;
+	CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
 }
 
 void
 CCutsceneMgr::SetupCutsceneToStart(void)
 {
-	TheCamera.SetCamCutSceneOffSet(ms_cutsceneOffset);
-	TheCamera.TakeControlWithSpline(JUMP_CUT);
+	TheCamera.SetCamCutSceneOffSet(ms_cutsceneOffset);
+	TheCamera.TakeControlWithSpline(JUMP_CUT);
 	TheCamera.SetWideScreenOn();
 
 	ms_cutsceneOffset.z++;
@@ -273,9 +274,9 @@ CCutsceneMgr::SetupCutsceneToStart(void)
 		}
 	}
 
-	CTimer::Update();
-	CTimer::Update();
-	ms_running = true;
+	CTimer::Update();
+	CTimer::Update();
+	ms_running = true;
 	ms_cutsceneTimer = 0.0f;
 }
 
@@ -297,14 +298,14 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject)
 	pAnimBlendClumpData->link.Prepend(&pNewAnim->link);
 }
 
-CCutsceneHead *
-CCutsceneMgr::AddCutsceneHead(CObject *pObject, int modelId)
-{
-	CCutsceneHead *pHead = new CCutsceneHead(pObject);
-	pHead->SetModelIndex(modelId);
-	CWorld::Add(pHead);
-	ms_pCutsceneObjects[ms_numCutsceneObjs++] = pHead;
-	return pHead;
+CCutsceneHead *
+CCutsceneMgr::AddCutsceneHead(CObject *pObject, int modelId)
+{
+	CCutsceneHead *pHead = new CCutsceneHead(pObject);
+	pHead->SetModelIndex(modelId);
+	CWorld::Add(pHead);
+	ms_pCutsceneObjects[ms_numCutsceneObjs++] = pHead;
+	return pHead;
 }
 
 CCutsceneObject *
@@ -333,89 +334,89 @@ CCutsceneMgr::CreateCutsceneObject(int modelId)
 
 	pCutsceneObject = new CCutsceneObject();
 	pCutsceneObject->SetModelIndex(modelId);
-	ms_pCutsceneObjects[ms_numCutsceneObjs++] = pCutsceneObject;
+	ms_pCutsceneObjects[ms_numCutsceneObjs++] = pCutsceneObject;
 	return pCutsceneObject;
 }
 
-void
-CCutsceneMgr::DeleteCutsceneData(void)
-{
-	if (!ms_loaded) return;
-
-	ms_cutsceneProcessing = false;
-	ms_useLodMultiplier = false;
-
-	for (--ms_numCutsceneObjs; ms_numCutsceneObjs >= 0; ms_numCutsceneObjs--) {
-		CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]);
-		ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject();
-		delete ms_pCutsceneObjects[ms_numCutsceneObjs];
-	}
-	ms_numCutsceneObjs = 0;
-
-	if (ms_animLoaded)
-		CAnimManager::RemoveLastAnimFile();
-
-	ms_animLoaded = false;
-	TheCamera.RestoreWithJumpCut();
-	TheCamera.SetWideScreenOff();
-	ms_running = false;
-	ms_loaded = false;
-
-	FindPlayerPed()->bIsVisible = true;
-	CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_80;
-	CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
-
-	if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
-		DMAudio.StopCutSceneMusic();
-		if (CGeneral::faststricmp(ms_cutsceneName, "bet"))
-			DMAudio.ChangeMusicMode(MUSICMODE_GAME);
-	}
-	CTimer::Stop();
-	//TheCamera.GetScreenFadeStatus() == 2; // what for??
-	CGame::DrasticTidyUpMemory();
-	CTimer::Update();
+void
+CCutsceneMgr::DeleteCutsceneData(void)
+{
+	if (!ms_loaded) return;
+
+	ms_cutsceneProcessing = false;
+	ms_useLodMultiplier = false;
+
+	for (--ms_numCutsceneObjs; ms_numCutsceneObjs >= 0; ms_numCutsceneObjs--) {
+		CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]);
+		ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject();
+		delete ms_pCutsceneObjects[ms_numCutsceneObjs];
+	}
+	ms_numCutsceneObjs = 0;
+
+	if (ms_animLoaded)
+		CAnimManager::RemoveLastAnimFile();
+
+	ms_animLoaded = false;
+	TheCamera.RestoreWithJumpCut();
+	TheCamera.SetWideScreenOff();
+	ms_running = false;
+	ms_loaded = false;
+
+	FindPlayerPed()->bIsVisible = true;
+	CPad::GetPad(0)->DisablePlayerControls &= ~PLAYERCONTROL_DISABLED_80;
+	CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
+
+	if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
+		DMAudio.StopCutSceneMusic();
+		if (CGeneral::faststricmp(ms_cutsceneName, "bet"))
+			DMAudio.ChangeMusicMode(MUSICMODE_GAME);
+	}
+	CTimer::Stop();
+	//TheCamera.GetScreenFadeStatus() == 2; // what for??
+	CGame::DrasticTidyUpMemory();
+	CTimer::Update();
 }
 
-void
-CCutsceneMgr::Update(void)
-{
-	enum {
-		CUTSCENE_LOADING_0 = 0,
-		CUTSCENE_LOADING_AUDIO,
-		CUTSCENE_LOADING_2,
-		CUTSCENE_LOADING_3,
-		CUTSCENE_LOADING_4
-	};
-
-	switch (ms_cutsceneLoadStatus) {
-	case CUTSCENE_LOADING_AUDIO:
-		SetupCutsceneToStart();
-		if (CGeneral::faststricmp(ms_cutsceneName, "end"))
-			DMAudio.PlayPreloadedCutSceneMusic();
-		ms_cutsceneLoadStatus++;
-		break;
-	case CUTSCENE_LOADING_2:
-	case CUTSCENE_LOADING_3:
-		ms_cutsceneLoadStatus++;
-		break;
-	case CUTSCENE_LOADING_4:
-		ms_cutsceneLoadStatus = CUTSCENE_LOADING_0;
-		break;
-	default:
-		break;
-	}
-
-	if (!ms_running) return;
-
-	ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f;
-	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())
-			|| CPad::GetPad(0)->GetLeftMouseJustDown()
-			|| CPad::GetPad(0)->GetEnterJustDown()
-			|| CPad::GetPad(0)->GetCharJustDown(VK_SPACE))
-			FinishCutscene();
-	}
+void
+CCutsceneMgr::Update(void)
+{
+	enum {
+		CUTSCENE_LOADING_0 = 0,
+		CUTSCENE_LOADING_AUDIO,
+		CUTSCENE_LOADING_2,
+		CUTSCENE_LOADING_3,
+		CUTSCENE_LOADING_4
+	};
+
+	switch (ms_cutsceneLoadStatus) {
+	case CUTSCENE_LOADING_AUDIO:
+		SetupCutsceneToStart();
+		if (CGeneral::faststricmp(ms_cutsceneName, "end"))
+			DMAudio.PlayPreloadedCutSceneMusic();
+		ms_cutsceneLoadStatus++;
+		break;
+	case CUTSCENE_LOADING_2:
+	case CUTSCENE_LOADING_3:
+		ms_cutsceneLoadStatus++;
+		break;
+	case CUTSCENE_LOADING_4:
+		ms_cutsceneLoadStatus = CUTSCENE_LOADING_0;
+		break;
+	default:
+		break;
+	}
+
+	if (!ms_running) return;
+
+	ms_cutsceneTimer += CTimer::GetTimeStepNonClipped() * 0.02f;
+	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())
+			|| CPad::GetPad(0)->GetLeftMouseJustDown()
+			|| CPad::GetPad(0)->GetEnterJustDown()
+			|| CPad::GetPad(0)->GetCharJustDown(VK_SPACE))
+			FinishCutscene();
+	}
 }
 
 bool CCutsceneMgr::HasCutsceneFinished(void) { return TheCamera.GetPositionAlongSpline() == 1.0f; }
diff --git a/src/core/Debug.cpp b/src/core/Debug.cpp
index bdcbaf04..2b713198 100644
--- a/src/core/Debug.cpp
+++ b/src/core/Debug.cpp
@@ -89,3 +89,49 @@ CDebug::DebugDisplayTextBuffer()
 	}
 #endif
 }
+
+
+// custom
+
+CDebug::ScreenStr CDebug::ms_aScreenStrs[MAX_SCREEN_STRS];
+int CDebug::ms_nScreenStrs;
+
+void
+CDebug::DisplayScreenStrings()
+{
+	int i;
+	
+
+	CFont::SetPropOn();
+	CFont::SetBackgroundOff();
+	CFont::SetScale(1.0f, 1.0f);
+	CFont::SetCentreOff();
+	CFont::SetRightJustifyOff();
+	CFont::SetJustifyOff();
+	CFont::SetRightJustifyWrap(0.0f);
+	CFont::SetWrapx(9999.0f);
+	CFont::SetBackGroundOnlyTextOff();
+	CFont::SetFontStyle(FONT_BANK);
+
+	for(i = 0; i < ms_nScreenStrs; i++){
+		AsciiToUnicode(ms_aScreenStrs[i].str, gUString);
+		CFont::SetColor(CRGBA(0, 0, 0, 255));
+		CFont::PrintString(ms_aScreenStrs[i].x, ms_aScreenStrs[i].y, gUString);
+		CFont::SetColor(CRGBA(255, 255, 255, 255));
+		CFont::PrintString(ms_aScreenStrs[i].x+1, ms_aScreenStrs[i].y+1, gUString);
+	}
+	CFont::DrawFonts();
+
+	ms_nScreenStrs = 0;
+}
+
+void
+CDebug::PrintAt(const char *str, int x, int y)
+{
+	if(ms_nScreenStrs >= MAX_SCREEN_STRS)
+		return;
+	strncpy(ms_aScreenStrs[ms_nScreenStrs].str, str, 256);
+	ms_aScreenStrs[ms_nScreenStrs].x = x*12;
+	ms_aScreenStrs[ms_nScreenStrs].y = y*22;
+	ms_nScreenStrs++;
+}
diff --git a/src/core/Debug.h b/src/core/Debug.h
index 444a0cf5..d169a0b4 100644
--- a/src/core/Debug.h
+++ b/src/core/Debug.h
@@ -6,15 +6,29 @@ class CDebug
 	{
 		MAX_LINES = 15,
 		MAX_STR_LEN = 80,
+
+		MAX_SCREEN_STRS = 100,
 	};
 
 	static int16 ms_nCurrentTextLine;
 	static char ms_aTextBuffer[MAX_LINES][MAX_STR_LEN];
 
+	// custom
+	struct ScreenStr {
+		int x, y;
+		char str[256];
+	};
+	static ScreenStr ms_aScreenStrs[MAX_SCREEN_STRS];
+	static int ms_nScreenStrs;
+
 public:
 	static void DebugInitTextBuffer();
 	static void DebugDisplayTextBuffer();
 	static void DebugAddText(const char *str);
+
+	// custom
+	static void PrintAt(const char *str, int x, int y);
+	static void DisplayScreenStrings();
 };
 
 extern bool gbDebugStuffInRelease;
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
index caf0cb3f..4364359a 100644
--- a/src/core/EventList.cpp
+++ b/src/core/EventList.cpp
@@ -5,10 +5,13 @@
 #include "World.h"
 #include "Wanted.h"
 #include "EventList.h"
+#include "Messages.h"
+#include "Text.h"
+#include "main.h"
 
 int32 CEventList::ms_nFirstFreeSlotIndex;
-//CEvent gaEvent[NUMEVENTS];
-CEvent *gaEvent = (CEvent*)0x6EF830;
+CEvent gaEvent[NUMEVENTS];
+//CEvent *gaEvent = (CEvent*)0x6EF830;
 
 enum
 {
@@ -207,8 +210,20 @@ CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCar
 	default: crime = CRIME_NONE; break;
 	}
 
-	if(crime == CRIME_NONE)
-		return;
+#ifdef VC_PED_PORTS
+	if (crime == CRIME_HIT_PED && ((CPed*)crimeId)->IsPointerValid() &&
+		FindPlayerPed()->m_pWanted->m_nWantedLevel == 0 && ((CPed*)crimeId)->m_ped_flagE2) {
+
+		if(!((CPed*)crimeId)->DyingOrDead()) {
+			sprintf(gString, "$50 Good Citizen Bonus!");
+			AsciiToUnicode(gString, gUString);
+			CMessages::AddBigMessage(gUString, 5000, 0);
+			CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 50;
+		}
+	} else
+#endif
+		if(crime == CRIME_NONE)
+			return;
 
 	CVector playerPedCoors = FindPlayerPed()->GetPosition();
 	CVector playerCoors = FindPlayerCoors();
diff --git a/src/core/EventList.h b/src/core/EventList.h
index 2799fca4..1c03c9d6 100644
--- a/src/core/EventList.h
+++ b/src/core/EventList.h
@@ -63,4 +63,4 @@ public:
 	static void ReportCrimeForEvent(eEventType type, int32, bool);
 };
 
-extern CEvent *gaEvent;
\ No newline at end of file
+extern CEvent gaEvent[NUMEVENTS];
\ No newline at end of file
diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp
index f83ad2c8..c98c808d 100644
--- a/src/core/Fire.cpp
+++ b/src/core/Fire.cpp
@@ -1,19 +1,289 @@
 #include "common.h"
 #include "patcher.h"
+#include "Vector.h"
+#include "PlayerPed.h"
+#include "Entity.h"
+#include "PointLights.h"
+#include "Particle.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "Shadows.h"
+#include "Automobile.h"
+#include "World.h"
+#include "General.h"
+#include "EventList.h"
+#include "DamageManager.h"
+#include "Ped.h"
 #include "Fire.h"
 
 CFireManager &gFireManager = *(CFireManager*)0x8F31D0;
 
-WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }
-WRAPPER void CFireManager::Update(void) { EAXJMP(0x479310); }
-WRAPPER CFire* CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); }
-
-uint32 CFireManager::GetTotalActiveFires() const
+CFire::CFire()
 {
-	return m_nTotalFires;
+	m_bIsOngoing = false;
+	m_bIsScriptFire = false;
+	m_bPropagationFlag = true;
+	m_bAudioSet = true;
+	m_vecPos = CVector(0.0f, 0.0f, 0.0f);
+	m_pEntity = nil;
+	m_pSource = nil;
+	m_nFiremenPuttingOut = 0;
+	m_nExtinguishTime = 0;
+	m_nStartTime = 0;
+	field_20 = 1;
+	m_nNextTimeToAddFlames = 0;
+	m_fStrength = 0.8f;
 }
 
-CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance)
+CFire::~CFire() {}
+
+void
+CFire::ProcessFire(void)
+{
+	float fDamagePlayer;
+	float fDamagePeds;
+	float fDamageVehicle;
+	int8 nRandNumber;
+	float fGreen;
+	float fRed;
+	CVector lightpos;
+	CVector firePos;
+	CPed *ped = (CPed *)m_pEntity;
+	CVehicle *veh = (CVehicle*)m_pEntity;
+
+	if (m_pEntity) {
+		m_vecPos = m_pEntity->GetPosition();
+
+		if (((CPed *)m_pEntity)->IsPed()) {
+			if (ped->m_pFire != this) {
+				Extinguish();
+				return;
+			}
+			if (ped->m_nMoveState != PEDMOVE_RUN)
+				m_vecPos.z -= 1.0f;
+			if (ped->bInVehicle && ped->m_pMyVehicle) {
+				if (ped->m_pMyVehicle->IsCar())
+					ped->m_pMyVehicle->m_fHealth = 75.0f;
+			} else if (m_pEntity == (CPed *)FindPlayerPed()) {
+				fDamagePlayer = 1.2f * CTimer::GetTimeStep();
+
+				((CPlayerPed *)m_pEntity)->InflictDamage(
+					(CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER,
+						fDamagePlayer, PEDPIECE_TORSO, 0);
+			} else {
+				fDamagePeds = 1.2f * CTimer::GetTimeStep();
+
+				if (((CPlayerPed *)m_pEntity)->InflictDamage(
+					(CPlayerPed *)m_pSource, WEAPONTYPE_FLAMETHROWER,
+					fDamagePeds, PEDPIECE_TORSO, 0)) {
+					m_pEntity->bRenderScorched = true;
+				}
+			}
+		} else if (m_pEntity->IsVehicle()) {
+			if (veh->m_pCarFire != this) {
+				Extinguish();
+				return;
+			}
+			if (!m_bIsScriptFire) {
+				fDamageVehicle = 1.2f * CTimer::GetTimeStep();
+				veh->InflictDamage((CVehicle *)m_pSource, WEAPONTYPE_FLAMETHROWER, fDamageVehicle);
+			}
+		}
+	}
+	if (!FindPlayerVehicle() && !FindPlayerPed()->m_pFire && !(FindPlayerPed()->bFireProof)
+		&& ((FindPlayerPed()->GetPosition() - m_vecPos).MagnitudeSqr() < 2.0f)) {
+		FindPlayerPed()->DoStuffToGoOnFire();
+		gFireManager.StartFire(FindPlayerPed(), m_pSource, 0.8f, 1);
+	}
+	if (CTimer::GetTimeInMilliseconds() > m_nNextTimeToAddFlames) {
+		m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + 80;
+		firePos = m_vecPos;
+
+		if (veh && veh->IsVehicle() && veh->IsCar()) {
+			CVehicleModelInfo *mi = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(veh->GetModelIndex()));
+			CVector ModelInfo = mi->m_positions[CAR_POS_HEADLIGHTS];
+			ModelInfo = m_pEntity->GetMatrix() * ModelInfo;
+
+			firePos.x = ModelInfo.x;
+			firePos.y = ModelInfo.y;
+			firePos.z = ModelInfo.z + 0.15f;
+		}
+
+		CParticle::AddParticle(PARTICLE_CARFLAME, firePos,
+			CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.0125f, 0.1f) * m_fStrength),
+				0, m_fStrength, 0, 0, 0, 0);
+
+		rand(); rand(); rand(); /* unsure why these three rands are called */
+
+		CParticle::AddParticle(PARTICLE_CARFLAME_SMOKE, firePos,
+			CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0);
+	}
+	if (CTimer::GetTimeInMilliseconds() < m_nExtinguishTime || m_bIsScriptFire) {
+		if (CTimer::GetTimeInMilliseconds() > m_nStartTime)
+			m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+
+		nRandNumber = CGeneral::GetRandomNumber() & 127;
+		lightpos.x = m_vecPos.x;
+		lightpos.y = m_vecPos.y;
+		lightpos.z = m_vecPos.z + 5.0f;
+
+		if (!m_pEntity) {
+			CShadows::StoreStaticShadow((uint32)this, SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &lightpos,
+				7.0f, 0.0f, 0.0f, -7.0f, 0, nRandNumber / 2, nRandNumber / 2,
+				0, 10.0f, 1.0f, 40.0f, 0, 0.0f);
+		}
+		fGreen = nRandNumber / 128;
+		fRed = nRandNumber / 128;
+
+		CPointLights::AddLight(0, m_vecPos, CVector(0.0f, 0.0f, 0.0f),
+			12.0f, fRed, fGreen, 0, 0, 0);
+	} else {
+		Extinguish();
+	}
+}
+
+void
+CFire::ReportThisFire(void)
+{
+	gFireManager.m_nTotalFires++;
+	CEventList::RegisterEvent(EVENT_FIRE, m_vecPos, 1000);
+}
+
+void
+CFire::Extinguish(void)
+{
+	if (m_bIsOngoing) {
+		if (!m_bIsScriptFire)
+			gFireManager.m_nTotalFires--;
+
+		m_nExtinguishTime = 0;
+		m_bIsOngoing = false;
+
+		if (m_pEntity) {
+			if (m_pEntity->IsPed()) {
+				((CPed *)m_pEntity)->RestorePreviousState();
+				((CPed *)m_pEntity)->m_pFire = nil;
+			} else if (m_pEntity->IsVehicle()) {
+				((CVehicle *)m_pEntity)->m_pCarFire = nil;
+			}
+			m_pEntity = nil;
+		}
+	}
+}
+
+void
+CFireManager::StartFire(CVector pos, float size, bool propagation)
+{
+	CFire *fire = GetNextFreeFire();
+
+	if (fire) {
+		fire->m_bIsOngoing = true;
+		fire->m_bIsScriptFire = false;
+		fire->m_bPropagationFlag = propagation;
+		fire->m_bAudioSet = true;
+		fire->m_vecPos = pos;
+		fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 10000;
+		fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+		fire->m_pEntity = nil;
+		fire->m_pSource = nil;
+		fire->m_nNextTimeToAddFlames = 0;
+		fire->ReportThisFire();
+		fire->m_fStrength = size;
+	}
+}
+
+CFire *
+CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation)
+{
+	CPed *ped = (CPed *)entityOnFire;
+	CVehicle *veh = (CVehicle *)entityOnFire;
+	
+	if (entityOnFire->IsPed()) {
+		if (ped->m_pFire)
+			return nil;
+		if (!ped->IsPedInControl())
+			return nil;
+	} else if (entityOnFire->IsVehicle()) {
+		if (veh->m_pCarFire)
+			return nil;
+		if (veh->IsCar() &&  ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225)
+			return nil;
+	}
+	CFire *fire = GetNextFreeFire();
+	
+	if (fire) {
+		if (entityOnFire->IsPed()) {
+			ped->m_pFire = fire;
+			if (ped != FindPlayerPed()) {
+				if (fleeFrom) {
+					ped->SetFlee(fleeFrom, 10000);
+				} else {
+					CVector2D pos = entityOnFire->GetPosition();
+					ped->SetFlee(pos, 10000);
+					ped->m_fleeFrom = nil;
+				}
+				ped->bDrawLast = false;
+				ped->SetMoveState(PEDMOVE_SPRINT);
+				ped->SetMoveAnim();
+				ped->m_nPedState = PED_ON_FIRE;
+			}
+			if (fleeFrom) {
+				if (ped->m_nPedType == PEDTYPE_COP) {
+					CEventList::RegisterEvent(EVENT_COP_SET_ON_FIRE, EVENT_ENTITY_PED,
+						entityOnFire, (CPed *)fleeFrom, 10000);
+				} else {
+					CEventList::RegisterEvent(EVENT_PED_SET_ON_FIRE, EVENT_ENTITY_PED,
+						entityOnFire, (CPed *)fleeFrom, 10000);
+				}
+			}
+		} else {
+			if (entityOnFire->IsVehicle()) {
+				veh->m_pCarFire = fire;
+				if (fleeFrom) {
+					CEventList::RegisterEvent(EVENT_CAR_SET_ON_FIRE, EVENT_ENTITY_VEHICLE,
+						entityOnFire, (CPed *)fleeFrom, 10000);	
+				}
+			}
+		}
+
+		fire->m_bIsOngoing = true;
+		fire->m_bIsScriptFire = false;
+		fire->m_vecPos = entityOnFire->GetPosition();
+
+		if (entityOnFire && entityOnFire->IsPed() && ped->IsPlayer()) {
+			fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + 3333;
+		} else if (entityOnFire->IsVehicle()) {
+			fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(4000, 5000);
+		} else {
+			fire->m_nExtinguishTime = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(10000, 11000);
+		}
+		fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+		fire->m_pEntity = entityOnFire;
+
+		entityOnFire->RegisterReference(&fire->m_pEntity);
+		fire->m_pSource = fleeFrom;
+
+		if (fleeFrom)
+			fleeFrom->RegisterReference(&fire->m_pSource);
+		fire->ReportThisFire();
+		fire->m_nNextTimeToAddFlames = 0;
+		fire->m_fStrength = strength;
+		fire->m_bPropagationFlag = propagation;
+		fire->m_bAudioSet = true;
+	}
+	return fire;
+}
+
+void
+CFireManager::Update(void)
+{
+	for (int i = 0; i < NUM_FIRES; i++) {
+		if (m_aFires[i].m_bIsOngoing)
+			m_aFires[i].ProcessFire();
+	}
+}
+
+CFire* CFireManager::FindNearestFire(CVector vecPos, float *pDistance)
 {
 	for (int i = 0; i < MAX_FIREMEN_ATTENDING; i++) {
 		int fireId = -1;
@@ -38,6 +308,44 @@ CFire* CFireManager::FindNearestFire(CVector vecPos, float* pDistance)
 	return nil;
 }
 
+CFire *
+CFireManager::FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange)
+{
+	int furthestFire = -1;
+	float lastFireDist = 0.0f;
+	float fireDist;
+
+	for (int i = 0; i < NUM_FIRES; i++) {
+		if (m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire) {
+			fireDist = (m_aFires[i].m_vecPos - coords).Magnitude2D();
+			if (fireDist > minRange && fireDist < maxRange && fireDist > lastFireDist) {
+				lastFireDist = fireDist;
+				furthestFire = i;
+			}
+		}
+	}
+	if (furthestFire == -1)
+		return nil;
+	else
+		return &m_aFires[furthestFire];
+}
+
+CFire *
+CFireManager::GetNextFreeFire(void)
+{
+	for (int i = 0; i < NUM_FIRES; i++) {
+		if (!m_aFires[i].m_bIsOngoing && !m_aFires[i].m_bIsScriptFire)
+			return &m_aFires[i];
+	}
+	return nil;
+}
+
+uint32
+CFireManager::GetTotalActiveFires(void) const
+{
+	return m_nTotalFires;
+}
+
 void
 CFireManager::ExtinguishPoint(CVector point, float range)
 {
@@ -49,16 +357,100 @@ CFireManager::ExtinguishPoint(CVector point, float range)
 	}
 }
 
-WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); }
-WRAPPER void CFireManager::StartFire(CVector, float, uint8) { EAXJMP(0x479500); }
-WRAPPER int32 CFireManager::StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8) { EAXJMP(0x479E60); }
-WRAPPER bool CFireManager::IsScriptFireExtinguish(int16) { EAXJMP(0x479FC0); }
-WRAPPER void CFireManager::RemoveScriptFire(int16) { EAXJMP(0x479FE0); }
-WRAPPER void CFireManager::RemoveAllScriptFires(void) { EAXJMP(0x47A000); }
-WRAPPER void CFireManager::SetScriptFireAudio(int16, bool) { EAXJMP(0x47A040); }
+int32
+CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation)
+{
+	CFire *fire;
+	CPed *ped = (CPed *)target;
+	CVehicle *veh = (CVehicle *)target;
+
+	if (target) {
+		if (target->IsPed()) {
+			if (ped->m_pFire)
+				ped->m_pFire->Extinguish();
+		} else if (target->IsVehicle()) {
+			if (veh->m_pCarFire)
+				veh->m_pCarFire->Extinguish();
+			if (veh->IsCar() && ((CAutomobile *)veh)->Damage.GetEngineStatus() >= 225) {
+				((CAutomobile *)veh)->Damage.SetEngineStatus(215);
+			}
+		}
+	}
+
+	fire = GetNextFreeFire();
+	fire->m_bIsOngoing = true;
+	fire->m_bIsScriptFire = true;
+	fire->m_bPropagationFlag = propagation;
+	fire->m_bAudioSet = true;
+	fire->m_vecPos = pos;
+	fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400;
+	fire->m_pEntity = target;
+
+	if (target)
+		target->RegisterReference(&fire->m_pEntity);
+	fire->m_pSource = nil;
+	fire->m_nNextTimeToAddFlames = 0;
+	fire->m_fStrength = strength;
+	if (target) {
+		if (target->IsPed()) {
+			ped->m_pFire = fire;
+			if (target != (CVehicle *)FindPlayerPed()) {
+				CVector2D pos = target->GetPosition();
+				ped->SetFlee(pos, 10000);
+				ped->SetMoveAnim();
+				ped->m_nPedState = PED_ON_FIRE;
+			}
+		} else if (target->IsVehicle()) {
+			veh->m_pCarFire = fire;
+		}
+	}
+	return fire - m_aFires;
+}
+
+bool
+CFireManager::IsScriptFireExtinguish(int16 index)
+{
+	return !m_aFires[index].m_bIsOngoing;
+}
+
+void
+CFireManager::RemoveAllScriptFires(void)
+{
+	for (int i = 0; i < NUM_FIRES; i++) {
+		if (m_aFires[i].m_bIsScriptFire) {
+			m_aFires[i].Extinguish();
+			m_aFires[i].m_bIsScriptFire = false;
+		}
+	}
+}
+
+void
+CFireManager::RemoveScriptFire(int16 index)
+{
+	m_aFires[index].Extinguish();
+	m_aFires[index].m_bIsScriptFire = false;
+}
+
+void
+CFireManager::SetScriptFireAudio(int16 index, bool state)
+{
+	m_aFires[index].m_bAudioSet = state;
+}
 
 STARTPATCHES
-	InjectHook(0x479DB0, &CFireManager::ExtinguishPoint, PATCH_JUMP);
+	InjectHook(0x4798D0, &CFire::ProcessFire, PATCH_JUMP);
+	InjectHook(0x4798B0, &CFire::ReportThisFire, PATCH_JUMP);
+	InjectHook(0x479D40, &CFire::Extinguish, PATCH_JUMP);
+	InjectHook(0x479500, (void(CFireManager::*)(CVector pos, float size, bool propagation))&CFireManager::StartFire, PATCH_JUMP);
+	InjectHook(0x479590, (CFire *(CFireManager::*)(CEntity *, CEntity *, float, bool))&CFireManager::StartFire, PATCH_JUMP);
+	InjectHook(0x479310, &CFireManager::Update, PATCH_JUMP);
+	InjectHook(0x479430, &CFireManager::FindFurthestFire_NeverMindFireMen, PATCH_JUMP);
 	InjectHook(0x479340, &CFireManager::FindNearestFire, PATCH_JUMP);
+	InjectHook(0x4792E0, &CFireManager::GetNextFreeFire, PATCH_JUMP);
+	InjectHook(0x479DB0, &CFireManager::ExtinguishPoint, PATCH_JUMP);
+	InjectHook(0x479E60, &CFireManager::StartScriptFire, PATCH_JUMP);
+	InjectHook(0x479FC0, &CFireManager::IsScriptFireExtinguish, PATCH_JUMP);
+	InjectHook(0x47A000, &CFireManager::RemoveAllScriptFires, PATCH_JUMP);
+	InjectHook(0x479FE0, &CFireManager::RemoveScriptFire, PATCH_JUMP);
+	InjectHook(0x47A040, &CFireManager::SetScriptFireAudio, PATCH_JUMP);
 ENDPATCHES
-
diff --git a/src/core/Fire.h b/src/core/Fire.h
index 624bf608..a4599d11 100644
--- a/src/core/Fire.h
+++ b/src/core/Fire.h
@@ -7,18 +7,22 @@ class CFire
 public:
 	bool m_bIsOngoing;
 	bool m_bIsScriptFire;
-	bool m_bPropogationFlag;
+	bool m_bPropagationFlag;
 	bool m_bAudioSet;
 	CVector m_vecPos;
 	CEntity *m_pEntity;
 	CEntity *m_pSource;
-	int m_nExtinguishTime;
-	int m_nStartTime;
-	int field_20;
-	int field_24;
+	uint32 m_nExtinguishTime;
+	uint32 m_nStartTime;
+	int32 field_20;
+	uint32 m_nNextTimeToAddFlames;
 	uint32 m_nFiremenPuttingOut;
-	float field_2C;
+	float m_fStrength;
 
+	CFire();
+	~CFire();
+	void ProcessFire(void);
+	void ReportThisFire(void);
 	void Extinguish(void);
 };
 
@@ -27,20 +31,21 @@ class CFireManager
 	enum {
 		MAX_FIREMEN_ATTENDING = 2,
 	};
-	uint32 m_nTotalFires;
 public:
+	uint32 m_nTotalFires;
 	CFire m_aFires[NUM_FIRES];
-	void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32);
-	void StartFire(CVector, float, uint8);
+	void StartFire(CVector pos, float size, bool propagation);
+	CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation);
 	void Update(void);
-	CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float);
-	CFire *FindNearestFire(CVector, float*);
+	CFire *FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange);
+	CFire *FindNearestFire(CVector vecPos, float *pDistance);
+	CFire *GetNextFreeFire(void);
 	uint32 GetTotalActiveFires() const;
-	void ExtinguishPoint(CVector, float);
-	int32 StartScriptFire(const CVector& pos, CEntity* culprit, float, uint8);
-	bool IsScriptFireExtinguish(int16);
-	void RemoveScriptFire(int16);
+	void ExtinguishPoint(CVector point, float range);
+	int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation);
+	bool IsScriptFireExtinguish(int16 index);
 	void RemoveAllScriptFires(void);
-	void SetScriptFireAudio(int16, bool);
+	void RemoveScriptFire(int16 index);
+	void SetScriptFireAudio(int16 index, bool state);
 };
 extern CFireManager &gFireManager;
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 4c2f3afa..aff8a3ec 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -181,6 +181,7 @@ ScaleAndCenterX(float x)
 #endif
 
 #define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS)
+
 #ifdef PS2_LIKE_MENU
 #define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \
 	do { \
@@ -235,67 +236,100 @@ ScaleAndCenterX(float x)
 			m_nHoverOption = HOVEROPTION_NOT_HOVERING; \
 	} while(0)
 
-#define ScrollUpListByOne() \
-	do { \
-		if (m_nSelectedListRow == m_nFirstVisibleRowOnList) { \
-			if (m_nFirstVisibleRowOnList > 0) { \
-				m_nSelectedListRow--; \
-				m_nFirstVisibleRowOnList--; \
-				m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow; \
-			} \
-		} else { \
-			m_nSelectedListRow--; \
-		} \
-	} while(0)
+// --- Functions not in the game/inlined starts
 
-#define ScrollDownListByOne() \
-	do { \
-		if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) { \
-			if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \
-				m_nSelectedListRow++; \
-				m_nFirstVisibleRowOnList++; \
-				m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow; \
-			} \
-		} else { \
-			if (m_nSelectedListRow < m_nTotalListRow - 1) { \
-				m_nSelectedListRow++; \
-			} \
-		} \
-	} while(0)
+inline void
+CMenuManager::ScrollUpListByOne() 
+{
+	if (m_nSelectedListRow == m_nFirstVisibleRowOnList) {
+		if (m_nFirstVisibleRowOnList > 0) {
+			m_nSelectedListRow--;
+			m_nFirstVisibleRowOnList--;
+			m_nCurListItemY -= LIST_HEIGHT / m_nTotalListRow;
+		}
+	} else {
+		m_nSelectedListRow--;
+	}
+}
 
-#define PageUpList(playSoundOnSuccess) \
-	do { \
-		if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \
-			if (m_nFirstVisibleRowOnList > 0) { \
-				if(playSoundOnSuccess) \
-					DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \
-				 \
-				m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW); \
-				m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1); \
-			} else { \
-				m_nFirstVisibleRowOnList = 0; \
-				m_nSelectedListRow = 0; \
-			} \
-			m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \
-		} \
-	} while(0)
+inline void
+CMenuManager::ScrollDownListByOne()
+{
+	if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) {
+		if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
+			m_nSelectedListRow++;
+			m_nFirstVisibleRowOnList++;
+			m_nCurListItemY += LIST_HEIGHT / m_nTotalListRow;
+		}
+	} else {
+		if (m_nSelectedListRow < m_nTotalListRow - 1) {
+			m_nSelectedListRow++;
+		}
+	}
+}
 
-#define PageDownList(playSoundOnSuccess) \
-	do { \
-		if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { \
-			if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { \
-				if(playSoundOnSuccess) \
-					DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); \
-				 \
-				m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW); \
-				m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList); \
-			} else { \
-				m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; \
-				m_nSelectedListRow = m_nTotalListRow - 1; \
-			} \
-			m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; \
-		} \
-	} while(0)
+inline void
+CMenuManager::PageUpList(bool playSoundOnSuccess)
+{
+	if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) {
+		if (m_nFirstVisibleRowOnList > 0) {
+			if(playSoundOnSuccess)
+				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+			m_nFirstVisibleRowOnList = max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW);
+			m_nSelectedListRow = min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1);
+		} else {
+			m_nFirstVisibleRowOnList = 0;
+			m_nSelectedListRow = 0;
+		}
+		m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+	}
+}
+
+inline void
+CMenuManager::PageDownList(bool playSoundOnSuccess)
+{
+	if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) {
+		if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) {
+			if(playSoundOnSuccess)
+				DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+
+			m_nFirstVisibleRowOnList = min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW);
+			m_nSelectedListRow = max(m_nSelectedListRow, m_nFirstVisibleRowOnList);
+		} else {
+			m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW;
+			m_nSelectedListRow = m_nTotalListRow - 1;
+		}
+		m_nCurListItemY = (LIST_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList;
+	}
+}
+
+inline void
+CMenuManager::ThingsToDoBeforeLeavingPage()
+{
+	if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) {
+		CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
+	} else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
+		if (m_nPrefsAudio3DProviderIndex != -1)
+			m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex();
+#ifdef TIDY_UP_PBP
+		DMAudio.StopFrontEndTrack();
+		OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
+#endif
+	} else if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) {
+		m_nDisplayVideoMode = m_nPrefsVideoMode;
+	}
+
+	if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
+		CPlayerSkin::EndFrontendSkinEdit();
+	}
+
+	if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) || (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS)) {
+		m_nTotalListRow = 0;
+	}
+}
+
+// ------ Functions not in the game/inlined ends
 
 void
 CMenuManager::BuildStatLine(char *text, void *stat, uint8 aFloat, void *stat2)
@@ -1173,7 +1207,6 @@ void CMenuManager::DrawFrontEnd()
 				bbNames[5] = { "FESZ_QU",MENUPAGE_EXIT };
 				bbTabCount = 6;
 			}
-			m_nCurrScreen = MENUPAGE_NEW_GAME;
 		} else {
 			if (bbTabCount != 8) {
 				bbNames[0] = { "FEB_STA",MENUPAGE_STATS };
@@ -1186,8 +1219,8 @@ void CMenuManager::DrawFrontEnd()
 				bbNames[7] = { "FESZ_QU",MENUPAGE_EXIT };
 				bbTabCount = 8;
 			}
-			m_nCurrScreen = MENUPAGE_STATS;
 		}
+		m_nCurrScreen = bbNames[0].screenId;
 		bottomBarActive = true;
 		curBottomBarOption = 0;
 	}
@@ -1285,7 +1318,6 @@ void CMenuManager::DrawFrontEndNormal()
 	eFrontendSprites currentSprite;
 	switch (m_nCurrScreen) {
 		case MENUPAGE_STATS:
-		case MENUPAGE_NEW_GAME:
 		case MENUPAGE_START_MENU:
 		case MENUPAGE_PAUSE_MENU:
 		case MENUPAGE_EXIT:
@@ -1315,7 +1347,7 @@ void CMenuManager::DrawFrontEndNormal()
 			currentSprite = FE_ICONCONTROLS;
 			break;
 		default:
-			/* actually MENUPAGE_NEW_GAME too*/
+			/*case MENUPAGE_NEW_GAME: */
 			/*case MENUPAGE_BRIEFS: */
 			currentSprite = FE_ICONBRIEF;
 			break;
@@ -1324,16 +1356,16 @@ void CMenuManager::DrawFrontEndNormal()
 	m_aFrontEndSprites[currentSprite].Draw(CRect(MENU_X_LEFT_ALIGNED(50.0f), MENU_Y(50.0f), MENU_X_RIGHT_ALIGNED(50.0f), SCREEN_SCALE_FROM_BOTTOM(95.0f)), CRGBA(255, 255, 255, m_nMenuFadeAlpha > 255 ? 255 : m_nMenuFadeAlpha));
 
 	if (m_nMenuFadeAlpha < 255) {
-		static int LastFade = 0;
+		static uint32 LastFade = 0;
 
 		if (m_nMenuFadeAlpha <= 0 && reverseAlpha) {
 			reverseAlpha = false;
 			ChangeScreen(pendingScreen, pendingOption, true, false);
-		} else if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
+		} else {
 			if (!reverseAlpha)
-				m_nMenuFadeAlpha += 20;
+				m_nMenuFadeAlpha += min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 20.0f;
 			else
-				m_nMenuFadeAlpha = max(m_nMenuFadeAlpha - 30, 0);
+				m_nMenuFadeAlpha = max(0, m_nMenuFadeAlpha - min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 30.0f);
 
 			LastFade = CTimer::GetTimeInMillisecondsPauseMode();
 		} 
@@ -1537,12 +1569,18 @@ void CMenuManager::DrawFrontEndNormal()
 	}
 
 	if (m_nMenuFadeAlpha < 255) {
-		static int LastFade = 0;
+		static uint32 LastFade = 0;
 
+		// Famous transparent menu bug. 33.0f = 1000.f/30.f (original frame limiter fps)
+#ifdef FIX_BUGS
+		m_nMenuFadeAlpha += min((CTimer::GetTimeInMillisecondsPauseMode() - LastFade) / 33.0f, 1.0f) * 20.0f;
+		LastFade = CTimer::GetTimeInMillisecondsPauseMode();
+#else
 		if(CTimer::GetTimeInMillisecondsPauseMode() - LastFade > 10){
 			m_nMenuFadeAlpha += 20;
 			LastFade = CTimer::GetTimeInMillisecondsPauseMode();
 		}
+#endif
 		
 		if (m_nMenuFadeAlpha > 255){
 			m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
@@ -1950,7 +1988,7 @@ WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); }
 #else
 void CMenuManager::Process(void)
 {
-	m_bMenuNotProcessed = false;
+	m_bMenuStateChanged = false;
 
 	if (!m_bSaveMenuActive && TheCamera.GetScreenFadeStatus() != FADE_0)
 		return;
@@ -2701,6 +2739,8 @@ CMenuManager::ProcessButtonPresses(void)
 		if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) {
 			DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
 			bottomBarActive = false;
+
+			// If there's a menu change with fade ongoing, finish it now
 			if (reverseAlpha)
 				m_nMenuFadeAlpha = 0;
 			return;
@@ -3116,51 +3156,43 @@ CMenuManager::ProcessButtonPresses(void)
 	if (goBack) {
 		CMenuManager::ResetHelperText();
 		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0);
-		if (m_nCurrScreen == MENUPAGE_PAUSE_MENU && !m_bGameNotLoaded && !m_bMenuNotProcessed){
-			if (CMenuManager::m_PrefsVsyncDisp != CMenuManager::m_PrefsVsync) {
-				CMenuManager::m_PrefsVsync = CMenuManager::m_PrefsVsyncDisp;
-			}
-			CMenuManager::RequestFrontEndShutDown();
-		} else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT
-#ifdef PS2_SAVE_DIALOG
-			|| m_nCurrScreen == MENUPAGE_SAVE
-#endif
-			) {
-			CMenuManager::RequestFrontEndShutDown();
-		} else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
-			DMAudio.StopFrontEndTrack();
-			OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
-		}
-
-		int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0];
-		int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0];
-
 #ifdef PS2_LIKE_MENU
-		if (bottomBarActive){
-			bottomBarActive = false;
-			if (!m_bGameNotLoaded) {
+		if (m_nCurrScreen == MENUPAGE_PAUSE_MENU || bottomBarActive) {
+#else
+		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;
 				}
 				CMenuManager::RequestFrontEndShutDown();
 			}
+
+			// We're already resuming, we don't need further processing.
+#if defined(FIX_BUGS) || defined(PS2_LIKE_MENU)
 			return;
+#endif
+		}
+#ifdef PS2_LIKE_MENU
+		else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT || m_nCurrScreen == MENUPAGE_SAVE) {
+#else
+		else if (m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT) {
+#endif
+			CMenuManager::RequestFrontEndShutDown();
+		}
+		// It's now in ThingsToDoBeforeLeavingPage()
+#ifndef TIDY_UP_PBP
+		else if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
+			DMAudio.StopFrontEndTrack();
+			OutputDebugString("FRONTEND AUDIO TRACK STOPPED");
 		}
 #endif
 
+		int oldScreen = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_PreviousPage[1] : aScreens[m_nCurrScreen].m_PreviousPage[0];
+		int oldOption = !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0];
+
 		if (oldScreen != -1) {
-			if ((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && strcmp(m_aSkinName, m_PrefsSkinFile) != 0) {
-				CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile);
-			}
-			if ((m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) && (m_nPrefsAudio3DProviderIndex != -1)) {
-				m_nPrefsAudio3DProviderIndex = DMAudio.GetCurrent3DProviderIndex();
-			}
-			if (m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS) {
-				m_nDisplayVideoMode = m_nPrefsVideoMode;
-			}
-			if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) {
-				CPlayerSkin::EndFrontendSkinEdit();
-			}
+			ThingsToDoBeforeLeavingPage();
 
 #ifdef PS2_LIKE_MENU
 			if (!bottomBarActive &&
@@ -3168,10 +3200,8 @@ CMenuManager::ProcessButtonPresses(void)
 				bottomBarActive = true;
 			} else
 #endif
+			{
 				ChangeScreen(oldScreen, oldOption, true, true);
-
-			if ((m_nPrevScreen == MENUPAGE_SKIN_SELECT) || (m_nPrevScreen == MENUPAGE_KEYBOARD_CONTROLS)) {
-				m_nTotalListRow = 0;
 			}
 
 			// We will go back for sure at this point, why process other things?!
@@ -3512,11 +3542,16 @@ WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); }
 #else
 void CMenuManager::SwitchMenuOnAndOff()
 {
-	if (!!(CPad::GetPad(0)->NewState.Start && !CPad::GetPad(0)->OldState.Start)
-		||  m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
+	bool menuWasActive = !!m_bMenuActive;
 
-		if (!m_bMenuActive)
-			m_bMenuActive = true;
+	// Reminder: You need REGISTER_START_BUTTON defined to make it work.
+	if (CPad::GetPad(0)->GetStartJustDown() 
+#ifdef FIX_BUGS
+		&& !m_bGameNotLoaded
+#endif
+		|| m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) {
+
+		m_bMenuActive = !m_bMenuActive;
 
 		if (m_bShutDownFrontEndRequested)
 			m_bMenuActive = false;
@@ -3525,8 +3560,13 @@ void CMenuManager::SwitchMenuOnAndOff()
 
 		if (m_bMenuActive) {
 			CTimer::StartUserPause();
-		}
-		else {
+		} else {
+#ifdef PS2_LIKE_MENU
+			bottomBarActive = false;
+#endif
+#ifdef FIX_BUGS
+			ThingsToDoBeforeLeavingPage();
+#endif
 			ShutdownJustMenu();
 			SaveSettings();
 			m_bStartUpFrontEndRequested = false;
@@ -3553,7 +3593,7 @@ void CMenuManager::SwitchMenuOnAndOff()
 		PcSaveHelper.PopulateSlotInfo();
 		m_nCurrOption = 0;
 	}
-/*	// Unused?
+/*	// PS2 leftover?
 	if (m_nCurrScreen != MENUPAGE_SOUND_SETTINGS && gMusicPlaying)
 	{
 		DMAudio.StopFrontEndTrack();
@@ -3561,8 +3601,8 @@ void CMenuManager::SwitchMenuOnAndOff()
 		gMusicPlaying = 0;
 	}
 */
-	if (!m_bMenuActive)
-		m_bMenuNotProcessed = true;
+	if (m_bMenuActive != menuWasActive)
+		m_bMenuStateChanged = true;
 
 	m_bStartUpFrontEndRequested = false;
 	m_bShutDownFrontEndRequested = false;
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 6d7327d3..3dbed164 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -403,7 +403,7 @@ public:
 	int32 m_nHelperTextMsgId;
 	bool m_bLanguageLoaded;
 	bool m_bMenuActive;
-	bool m_bMenuNotProcessed;
+	bool m_bMenuStateChanged;
 	bool m_bWaitingForNewKeyBind;
 	bool m_bStartGameLoading;
 	bool m_bFirstTime;
@@ -540,8 +540,14 @@ public:
 	void WaitForUserCD();
 	void PrintController();
 
-	// New content:
-	uint8 GetNumberOfMenuOptions();
+	// New (not in function or inlined in the game)
+	void ThingsToDoBeforeLeavingPage();
+	void ScrollUpListByOne();
+	void ScrollDownListByOne();
+	void PageUpList(bool);
+	void PageDownList(bool);
+	
+	// uint8 GetNumberOfMenuOptions();
 };
 
 static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");
diff --git a/src/core/General.h b/src/core/General.h
index a7b240c2..f32846eb 100644
--- a/src/core/General.h
+++ b/src/core/General.h
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <ctype.h>
+
 class CGeneral
 {
 public:
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index 51102c7b..87f45b9f 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -5,6 +5,10 @@
 #pragma warning( pop )
 
 #include "common.h"
+#ifdef XINPUT
+#include <Xinput.h>
+#pragma comment( lib, "Xinput9_1_0.lib" )
+#endif
 #include "patcher.h"
 #include "Pad.h"
 #include "ControllerConfig.h"
@@ -547,12 +551,78 @@ void CPad::AddToPCCheatString(char c)
 	#undef _CHEATCMP
 }
 
+#ifdef XINPUT
+void CPad::AffectFromXinput(uint32 pad)
+{
+	XINPUT_STATE xstate;
+	memset(&xstate, 0, sizeof(XINPUT_STATE));
+	if (XInputGetState(pad, &xstate) == ERROR_SUCCESS)
+	{
+		PCTempJoyState.Circle = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 255 : 0;
+		PCTempJoyState.Cross = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 255 : 0;
+		PCTempJoyState.Square = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 255 : 0;
+		PCTempJoyState.Triangle = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 255 : 0;
+		PCTempJoyState.DPadDown = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) ? 255 : 0;
+		PCTempJoyState.DPadLeft = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) ? 255 : 0;
+		PCTempJoyState.DPadRight = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) ? 255 : 0;
+		PCTempJoyState.DPadUp = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) ? 255 : 0;
+		PCTempJoyState.LeftShock = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 255 : 0;
+		PCTempJoyState.LeftShoulder1 = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 255 : 0;
+		PCTempJoyState.LeftShoulder2 = xstate.Gamepad.bLeftTrigger;
+		PCTempJoyState.RightShock = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 255 : 0;
+		PCTempJoyState.RightShoulder1 = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 255 : 0;
+		PCTempJoyState.RightShoulder2 = xstate.Gamepad.bRightTrigger;
+
+		PCTempJoyState.Select = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 255 : 0;
+		PCTempJoyState.Start = (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 255 : 0;
+
+		float lx = (float)xstate.Gamepad.sThumbLX / (float)0x7FFF;
+		float ly = (float)xstate.Gamepad.sThumbLY / (float)0x7FFF;
+		float rx = (float)xstate.Gamepad.sThumbRX / (float)0x7FFF;
+		float ry = (float)xstate.Gamepad.sThumbRY / (float)0x7FFF;
+
+		if (Abs(lx) > 0.3f || Abs(ly) > 0.3f) {
+			PCTempJoyState.LeftStickX = (int32)(lx * 128.0f);
+			PCTempJoyState.LeftStickY = (int32)(-ly * 128.0f);
+		}
+
+		if (Abs(rx) > 0.3f || Abs(ry) > 0.3f) {
+			PCTempJoyState.RightStickX = (int32)(rx * 128.0f);
+			PCTempJoyState.RightStickY = (int32)(ry * 128.0f);
+		}
+
+		XINPUT_VIBRATION VibrationState;
+
+		memset(&VibrationState, 0, sizeof(XINPUT_VIBRATION));
+
+		uint16 iLeftMotor = (uint16)((float)ShakeFreq / 255.0f * (float)0xffff);
+		uint16 iRightMotor = (uint16)((float)ShakeFreq / 255.0f * (float)0xffff);
+		
+		if (ShakeDur < CTimer::GetTimeStepInMilliseconds())
+			ShakeDur = 0;
+		else
+			ShakeDur -= CTimer::GetTimeStepInMilliseconds();
+		if (ShakeDur == 0) ShakeFreq = 0;
+
+		VibrationState.wLeftMotorSpeed = iLeftMotor;
+		VibrationState.wRightMotorSpeed = iRightMotor;
+
+		XInputSetState(pad, &VibrationState);
+	}
+}
+#endif
+
 void CPad::UpdatePads(void) 
 {
 	bool bUpdate = true;
 	
 	GetPad(0)->UpdateMouse();
+#ifdef XINPUT
+	GetPad(0)->AffectFromXinput(0);
+	GetPad(1)->AffectFromXinput(1);
+#else
 	CapturePad(0);
+#endif
 	
 
 	ControlsManager.ClearSimButtonPressCheckers();
@@ -565,10 +635,13 @@ void CPad::UpdatePads(void)
 	if ( bUpdate )
 	{
 		GetPad(0)->Update(0);
+		GetPad(1)->Update(0);
 	}
-	
+
+#if defined(MASTER) && !defined(XINPUT)
 	GetPad(1)->NewState.Clear();
 	GetPad(1)->OldState.Clear();
+#endif
 	
 	OldKeyState = NewKeyState;
 	NewKeyState = TempKeyState;
diff --git a/src/core/Pad.h b/src/core/Pad.h
index a231900e..84919f32 100644
--- a/src/core/Pad.h
+++ b/src/core/Pad.h
@@ -247,6 +247,10 @@ public:
 	static char *EditString(char *pStr, int32 nSize);
 	static int32 *EditCodesForControls(int32 *pRsKeys, int32 nSize);
 
+#ifdef XINPUT
+	void AffectFromXinput(uint32 pad);
+#endif
+
 	// mouse
 	bool GetLeftMouseJustDown()           { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); }
 	bool GetRightMouseJustDown()          { return !!(NewMouseControllerState.RMB && !OldMouseControllerState.RMB); }
@@ -399,6 +403,8 @@ public:
 	bool GetLeftShoulder2JustDown()  { return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); }
 	bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); }
 	bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); }
+	bool GetLeftShockJustDown()      { return !!(NewState.LeftShock && !OldState.LeftShock); }
+	bool GetRightShockJustDown()     { return !!(NewState.RightShock && !OldState.RightShock); }
 	bool GetStartJustDown()          { return !!(NewState.Start && !OldState.Start); }
 	bool GetLeftStickXJustDown() { return !!(NewState.LeftStickX && !OldState.LeftStickX); }
 	bool GetLeftStickYJustDown() { return !!(NewState.LeftStickY && !OldState.LeftStickY); }
@@ -422,6 +428,10 @@ public:
 	bool GetLeftShoulder2(void)  { return !!NewState.LeftShoulder2; }
 	bool GetRightShoulder1(void) { return !!NewState.RightShoulder1; }
 	bool GetRightShoulder2(void) { return !!NewState.RightShoulder2; }
+	int16 GetLeftStickX(void)    { return NewState.LeftStickX; }
+	int16 GetLeftStickY(void)    { return NewState.LeftStickY; }
+	int16 GetRightStickX(void)    { return NewState.RightStickX; }
+	int16 GetRightStickY(void)    { return NewState.RightStickY; }
 
 	bool ArePlayerControlsDisabled(void) { return DisablePlayerControls != PLAYERCONTROL_ENABLED; }
 	void SetDisablePlayerControls(uint8 who) { DisablePlayerControls |= who; }
diff --git a/src/core/Placeable.cpp b/src/core/Placeable.cpp
index d2cec82b..c882fc27 100644
--- a/src/core/Placeable.cpp
+++ b/src/core/Placeable.cpp
@@ -63,6 +63,8 @@ CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float
 	       z1 <= GetPosition().z && GetPosition().z <= z2;
 }
 
+#include <new>
+
 class CPlaceable_ : public CPlaceable
 {
 public:
diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp
index 3a830d37..6106f3df 100644
--- a/src/core/Streaming.cpp
+++ b/src/core/Streaming.cpp
@@ -198,7 +198,7 @@ CStreaming::Init(void)
 	// PC only, figure out how much memory we got
 #ifdef GTA_PC
 #define MB (1024*1024)
-	extern DWORD &_dwMemAvailPhys;
+	extern unsigned long &_dwMemAvailPhys;
 	ms_memoryAvailable = (_dwMemAvailPhys - 10*MB)/2;
 	if(ms_memoryAvailable < 50*MB)
 		ms_memoryAvailable = 50*MB;
diff --git a/src/core/Timer.h b/src/core/Timer.h
index 89c4a430..ef525be7 100644
--- a/src/core/Timer.h
+++ b/src/core/Timer.h
@@ -2,7 +2,7 @@
 
 class CTimer
 {
-public:
+
 	static uint32 &m_snTimeInMilliseconds;
 	static uint32 &m_snTimeInMillisecondsPauseMode;
 	static uint32 &m_snTimeInMillisecondsNonClipped;
@@ -11,19 +11,20 @@ public:
 	static float &ms_fTimeScale;
 	static float &ms_fTimeStep;
 	static float &ms_fTimeStepNonClipped;
+public:
 	static bool  &m_UserPause;
 	static bool  &m_CodePause;
 
-	static float GetTimeStep(void) { return ms_fTimeStep; }
+	static const float &GetTimeStep(void) { return ms_fTimeStep; }
 	static void SetTimeStep(float ts) { ms_fTimeStep = ts; }
 	static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; }
 	static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; }
-	static float GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
+	static const float &GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; }
 	static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; }
 	static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; }
-	static uint32 GetFrameCounter(void) { return m_FrameCounter; }
+	static const uint32 &GetFrameCounter(void) { return m_FrameCounter; }
 	static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; }
-	static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; }
+	static const uint32 &GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; }
 	static void SetTimeInMilliseconds(uint32 t) { m_snTimeInMilliseconds = t; }
 	static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; }
 	static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; }
@@ -31,7 +32,7 @@ public:
 	static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; }
 	static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; }
 	static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; }
-	static float GetTimeScale(void) { return ms_fTimeScale; }
+	static const float &GetTimeScale(void) { return ms_fTimeScale; }
 	static void SetTimeScale(float ts) { ms_fTimeScale = ts; }
 
 	static bool GetIsPaused() { return m_UserPause || m_CodePause; }
diff --git a/src/core/World.cpp b/src/core/World.cpp
index 1832ce72..769bd9ad 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -20,11 +20,12 @@
 #include "Replay.h"
 #include "Population.h"
 
+CColPoint *gaTempSphereColPoints = (CColPoint*)0x6E64C0;	// [32]
+
 CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60;
 CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C;
 CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608;
 uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64;
-CColPoint &CWorld::ms_testSpherePoint = *(CColPoint*)0x6E64C0;
 
 uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61;
 CPlayerInfo (&CWorld::Players)[NUMPLAYERS] = *(CPlayerInfo (*)[NUMPLAYERS])*(uintptr*)0x9412F0;
@@ -610,9 +611,9 @@ CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bo
 }
 
 void
-CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects)
+CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects)
 {
-	float distSqr = distance * distance;
+	float radiusSqr = radius * radius;
 	float objDistSqr;
 
 	for (CPtrNode *node = list.first; node; node = node->next) {
@@ -626,7 +627,7 @@ CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float dist
 			else
 				objDistSqr = diff.MagnitudeSqr();
 
-			if (objDistSqr < distSqr && *nextObject < lastObject) {
+			if (objDistSqr < radiusSqr && *nextObject < lastObject) {
 				if (objects) {
 					objects[*nextObject] = object;
 				}
@@ -637,22 +638,22 @@ CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float dist
 }
 
 void
-CWorld::FindObjectsInRange(CVector &centre, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
+CWorld::FindObjectsInRange(CVector &centre, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
 {
-	int minX = GetSectorIndexX(centre.x - distance);
+	int minX = GetSectorIndexX(centre.x - radius);
 	if (minX <= 0) minX = 0;
 
-	int minY = GetSectorIndexY(centre.y - distance);
+	int minY = GetSectorIndexY(centre.y - radius);
 	if (minY <= 0) minY = 0;
 
-	int maxX = GetSectorIndexX(centre.x + distance);
+	int maxX = GetSectorIndexX(centre.x + radius);
 #ifdef FIX_BUGS
 	if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
 #else
 	if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
 #endif
 
-	int maxY = GetSectorIndexY(centre.y + distance);
+	int maxY = GetSectorIndexY(centre.y + radius);
 #ifdef FIX_BUGS
 	if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
 #else
@@ -666,48 +667,48 @@ CWorld::FindObjectsInRange(CVector &centre, float distance, bool ignoreZ, short
 		for(int curX = minX; curX <= maxX; curX++) {
 			CSector *sector = GetSector(curX, curY);
 			if (checkBuildings) {
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects);
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
 			}
 			if (checkVehicles) {
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects);
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
 			}
 			if (checkPeds) {
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects);
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
 			}
 			if (checkObjects) {
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects);
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
 			}
 			if (checkDummies) {
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects);
-				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, ignoreZ, nextObject, lastObject, objects);
+				FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
 			}
 		}
 	}
 }
 
 CEntity*
-CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects)
+CWorld::TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects)
 {
 	CEntity* foundE = nil;
 
-	int minX = GetSectorIndexX(centre.x - distance);
+	int minX = GetSectorIndexX(centre.x - radius);
 	if (minX <= 0) minX = 0;
 
-	int minY = GetSectorIndexY(centre.y - distance);
+	int minY = GetSectorIndexY(centre.y - radius);
 	if (minY <= 0) minY = 0;
 
-	int maxX = GetSectorIndexX(centre.x + distance);
+	int maxX = GetSectorIndexX(centre.x + radius);
 #ifdef FIX_BUGS
 	if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
 #else
 	if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
 #endif
 
-	int maxY = GetSectorIndexY(centre.y + distance);
+	int maxY = GetSectorIndexY(centre.y + radius);
 #ifdef FIX_BUGS
 	if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
 #else
@@ -720,47 +721,47 @@ CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityTo
 		for (int curX = minX; curX <= maxX; curX++) {
 			CSector* sector = GetSector(curX, curY);
 			if (checkBuildings) {
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 			}
 			if (checkVehicles) {
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 			}
 			if (checkPeds) {
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 			}
 			if (checkObjects) {
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, entityToIgnore, ignoreSomeObjects);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, entityToIgnore, ignoreSomeObjects);
 				if (foundE)
 					return foundE;
 
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, entityToIgnore, ignoreSomeObjects);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, entityToIgnore, ignoreSomeObjects);
 				if (foundE)
 					return foundE;
 			}
 			if (checkDummies) {
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 
-				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, entityToIgnore, false);
+				foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, entityToIgnore, false);
 				if (foundE)
 					return foundE;
 			}
@@ -807,7 +808,7 @@ CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float rad
 				if (e->GetBoundRadius() + radius > distance) {
 					CColModel *eCol = CModelInfo::GetModelInfo(e->m_modelIndex)->GetColModel();
 					int collidedSpheres = CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(),
-						*eCol, &ms_testSpherePoint, nil, nil);
+						*eCol, gaTempSphereColPoints, nil, nil);
 
 					if (collidedSpheres != 0 ||
 						(e->IsVehicle() && ((CVehicle*)e)->m_vehType == VEHICLE_TYPE_CAR &&
diff --git a/src/core/World.h b/src/core/World.h
index 75d17a71..3fcbc301 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -60,8 +60,6 @@ class CWorld
 	static uint16 &ms_nCurrentScanCode;
 
 public:
-	static CColPoint& ms_testSpherePoint;
-
 	static uint8 &PlayerInFocus;
 	static CPlayerInfo (&Players)[NUMPLAYERS];
 	static CEntity *&pIgnoreEntity;
@@ -101,7 +99,7 @@ public:
 	static bool GetIsLineOfSightSectorClear(CSector &sector, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
 	static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
 	
-	static CEntity *TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects);
+	static CEntity *TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects);
 	static CEntity *TestSphereAgainstSectorList(CPtrList&, CVector, float, CEntity*, bool);
 	static void FindObjectsInRangeSectorList(CPtrList&, CVector&, float, bool, short*, short, CEntity**);
 	static void FindObjectsInRange(CVector&, float, bool, short*, short, CEntity**, bool, bool, bool, bool, bool);
@@ -142,6 +140,8 @@ public:
 	static void Process();
 };
 
+extern CColPoint *gaTempSphereColPoints;
+
 class CPlayerPed;
 class CVehicle;
 CPlayerPed *FindPlayerPed(void);
diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp
index 363fc3d9..4bce3e79 100644
--- a/src/core/Zones.cpp
+++ b/src/core/Zones.cpp
@@ -1,5 +1,6 @@
 #include "common.h"
 #include "patcher.h"
+#include <ctype.h>
 
 #include "Zones.h"
 
diff --git a/src/core/common.h b/src/core/common.h
index 3127cb12..7b4ff4a0 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -8,9 +8,12 @@
 #pragma warning(disable: 4996)  // POSIX names
 
 #include <stdint.h>
+#include <string.h>
 #include <math.h>
-//#include <assert.h>
-#include <new>
+
+#ifdef WITHWINDOWS
+#include <Windows.h>
+#endif
 
 #ifdef WITHD3D
 #include <windows.h>
@@ -30,6 +33,16 @@
 #undef near
 #endif
 
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
+#endif
+
 typedef uint8_t uint8;
 typedef int8_t int8;
 typedef uint16_t uint16;
diff --git a/src/core/config.h b/src/core/config.h
index 54a4c25f..d4e85f7c 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -101,6 +101,8 @@ enum Config {
 	NUMPEDGROUPS = 31,
 	NUMMODELSPERPEDGROUP = 8,
 
+	NUMROADBLOCKS = 600,
+
 	NUMVISIBLEENTITIES = 2000,
 	NUMINVISIBLEENTITIES = 150,
 
@@ -171,10 +173,12 @@ enum Config {
 #endif
 
 #define FIX_BUGS		// fixes bugs that we've came across during reversing, TODO: use this more
-#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. doesn't have too many things
+#define TOGGLEABLE_BETA_FEATURES // toggleable from debug menu. not too many things
 
 // Pad
+#define XINPUT
 #define KANGAROO_CHEAT
+#define REGISTER_START_BUTTON // currently only in menu sadly. resumes the game
 
 // Hud, frontend and radar
 #define ASPECT_RATIO_SCALE	// Not just makes everything scale with aspect ratio, also adds support for all aspect ratios
@@ -201,5 +205,7 @@ enum Config {
 // Peds
 #define ANIMATE_PED_COL_MODEL
 #define VC_PED_PORTS			// various ports from VC's CPed, mostly subtle
-#define NEW_WALK_AROUND_ALGORITHM	// to make walking around vehicles/objects less awkward
+// #define NEW_WALK_AROUND_ALGORITHM	// to make walking around vehicles/objects less awkward
 #define CANCELLABLE_CAR_ENTER
+
+#define IMPROVED_CAMERA		// Better Debug cam, and maybe more in the future
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 2a15e20e..663b09da 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -325,6 +325,7 @@ DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16
 void
 DoRWStuffEndOfFrame(void)
 {
+	CDebug::DisplayScreenStrings();	// custom
 	CDebug::DebugDisplayTextBuffer();
 	// FlushObrsPrintfs();
 	RwCameraEndUpdate(Scene.camera);
diff --git a/src/core/patcher.h b/src/core/patcher.h
index 87a6bea4..3dfbb05c 100644
--- a/src/core/patcher.h
+++ b/src/core/patcher.h
@@ -6,13 +6,7 @@
 #define VARJMP(a) { _asm jmp a }
 #define WRAPARG(a) UNREFERENCED_PARAMETER(a)
 
-#define NOVMT __declspec(novtable)
-#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a
-
-#include <algorithm>
-#include <vector>
-
-#include "common.h"
+#include <string.h>	//memset
 
 enum
 {
@@ -103,72 +97,36 @@ isVC(void)
 	InjectHook(a, func); \
 }
 
+void InjectHook_internal(uint32 address, uint32 hook, int type);
+void Protect_internal(uint32 address, uint32 size);
+void Unprotect_internal(void);
+
 template<typename T, typename AT> inline void
 Patch(AT address, T value)
 {
-	DWORD		dwProtect[2];
-	VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
+	Protect_internal((uint32)address, sizeof(T));
 	*(T*)address = value;
-	VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]);
+	Unprotect_internal();
 }
 
 template<typename AT> inline void
 Nop(AT address, unsigned int nCount)
 {
-	DWORD		dwProtect[2];
-	VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
+	Protect_internal((uint32)address, nCount);
 	memset((void*)address, 0x90, nCount);
-	VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]);
+	Unprotect_internal();
 }
 
-template<typename AT> inline void
-ClearCC(AT address, unsigned int nCount)
-{
-	DWORD		dwProtect[2];
-	VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
-	memset((void*)address, 0xCC, nCount);
-	VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]);
-}
-
-extern std::vector<int32> usedAddresses;
-
 template<typename AT, typename HT> inline void
 InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING)
 {
-	if(std::any_of(usedAddresses.begin(), usedAddresses.end(),
-	               [address](AT value) { return (int32)value == address; })) {
-		debug("Used address %#06x twice when injecting hook\n", address);
-	}
-
-	usedAddresses.push_back((int32)address);
-
-	DWORD		dwProtect[2];
-	switch ( nType )
-	{
-	case PATCH_JUMP:
-		VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
-		*(BYTE*)address = 0xE9;
-		break;
-	case PATCH_CALL:
-		VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
-		*(BYTE*)address = 0xE8;
-		break;
-	default:
-		VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]);
-		break;
-	}
-	DWORD		dwHook;
+	uint32		uiHook;
 	_asm
 	{
 		mov		eax, hook
-		mov		dwHook, eax
+		mov		uiHook, eax
 	}
-
-	*(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5;
-	if ( nType == PATCH_NOTHING )
-		VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]);
-	else
-		VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]);
+	InjectHook_internal((uint32)address, uiHook, nType);
 }
 
 inline void ExtractCall(void *dst, uint32_t a)
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 6f0a4682..137a890c 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -20,12 +20,64 @@
 #include "debugmenu_public.h"
 #include "Particle.h"
 #include "Console.h"
+#include "Debug.h"
 
+#include <algorithm>
 #include <vector>
 #include <list>
 
 std::vector<int32> usedAddresses;
 
+static DWORD protect[2];
+static uint32 protect_address;
+static uint32 protect_size;
+
+void
+Protect_internal(uint32 address, uint32 size)
+{
+	protect_address = address;
+	protect_size = size;
+	VirtualProtect((void*)address, size, PAGE_EXECUTE_READWRITE, &protect[0]);
+}
+
+void
+Unprotect_internal(void)
+{
+	VirtualProtect((void*)protect_address, protect_size, protect[0], &protect[1]);
+}
+
+void
+InjectHook_internal(uint32 address, uint32 hook, int type)
+{
+	if(std::any_of(usedAddresses.begin(), usedAddresses.end(),
+	               [address](uint32 value) { return (int32)value == address; })) {
+		debug("Used address %#06x twice when injecting hook\n", address);
+	}
+
+	usedAddresses.push_back((int32)address);
+
+
+	switch(type){
+	case PATCH_JUMP:
+		VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &protect[0]);
+		*(uint8*)address = 0xE9;
+		break;
+	case PATCH_CALL:
+		VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &protect[0]);
+		*(uint8*)address = 0xE8;
+		break;
+	default:
+		VirtualProtect((void*)((uint32)address + 1), 4, PAGE_EXECUTE_READWRITE, &protect[0]);
+		break;
+	}
+
+	*(ptrdiff_t*)(address + 1) = hook - address - 5;
+	if(type == PATCH_NOTHING)
+		VirtualProtect((void*)(address + 1), 4, protect[0], &protect[1]);
+	else
+		VirtualProtect((void*)address, 5, protect[0], &protect[1]);
+}
+
 void **rwengine = *(void***)0x5A10E1;
 
 DebugMenuAPI gDebugMenuAPI;
@@ -114,13 +166,16 @@ SpawnCar(int id)
 	CStreaming::LoadAllRequestedModels(false);
 	if(CStreaming::HasModelLoaded(id)){
 		playerpos = FindPlayerCoors();
-		int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false);
-		if(node < 0)
-			return;
+		int node;
+		if(!CModelInfo::IsBoatModel(id)){
+			node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false);
+			if(node < 0)
+				return;
+		}
 
 		CVehicle *v;
 		if(CModelInfo::IsBoatModel(id))
-			return;
+			v = new CBoat(id, RANDOM_VEHICLE);
 		else
 			v = new CAutomobile(id, RANDOM_VEHICLE);
 
@@ -130,7 +185,11 @@ SpawnCar(int id)
 		if(carCol2)
 			DebugMenuEntrySetAddress(carCol2, &v->m_currentColour2);
 
-		v->GetPosition() = ThePaths.m_pathNodes[node].pos;
+		if(CModelInfo::IsBoatModel(id))
+			v->GetPosition() = TheCamera.GetPosition() + TheCamera.GetForward()*15.0f;
+		else
+			v->GetPosition() = ThePaths.m_pathNodes[node].pos;
+
 		v->GetPosition().z += 4.0f;
 		v->SetOrientation(0.0f, 0.0f, 3.49f);
 		v->m_status = STATUS_ABANDONED;
@@ -197,6 +256,12 @@ PlaceOnRoad(void)
 		((CAutomobile*)veh)->PlaceOnRoadProperly();
 }
 
+static void
+ResetCamStatics(void)
+{
+	TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true;
+}
+
 static const char *carnames[] = {
 	"landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony",
 	"mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer",
@@ -358,7 +423,17 @@ DebugMenuPopulate(void)
 
 		DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
 		DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
-		
+
+		extern bool PrintDebugCode;
+		extern int16 &DebugCamMode;
+		DebugMenuAddVarBool8("Cam", "Print Debug Code", (int8*)&PrintDebugCode, nil);
+		DebugMenuAddVar("Cam", "Cam Mode", &DebugCamMode, nil, 1, 0, CCam::MODE_EDITOR, nil);
+		DebugMenuAddCmd("Cam", "Normal", []() { DebugCamMode = 0; });
+		DebugMenuAddCmd("Cam", "Follow Ped With Bind", []() { DebugCamMode = CCam::MODE_FOLLOW_PED_WITH_BIND; });
+		DebugMenuAddCmd("Cam", "Reaction", []() { DebugCamMode = CCam::MODE_REACTION; });
+		DebugMenuAddCmd("Cam", "Chris", []() { DebugCamMode = CCam::MODE_CHRIS; });
+		DebugMenuAddCmd("Cam", "Reset Statics", ResetCamStatics);
+
 		CTweakVars::AddDBG("Debug");
 	}
 }
@@ -433,7 +508,8 @@ 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);
 }
 
 void re3_trace(const char *filename, unsigned int lineno, const char *func, const char *format, ...)
diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp
index 188cbfe7..7813c87f 100644
--- a/src/entities/Building.cpp
+++ b/src/entities/Building.cpp
@@ -21,6 +21,8 @@ CBuilding::ReplaceWithNewModel(int32 id)
 			CStreaming::RequestModel(id, STREAMFLAGS_DONT_REMOVE);
 }
 
+#include <new>
+
 class CBuilding_ : public CBuilding
 {
 public:
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 04a93420..8bec1ac8 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -865,6 +865,8 @@ CEntity::ModifyMatrixForBannerInWind(void)
 	UpdateRwFrame();
 }
 
+#include <new>
+
 class CEntity_ : public CEntity
 {
 public:
diff --git a/src/objects/DummyObject.cpp b/src/objects/DummyObject.cpp
index 9649cf7a..ba09ac3e 100644
--- a/src/objects/DummyObject.cpp
+++ b/src/objects/DummyObject.cpp
@@ -12,6 +12,8 @@ CDummyObject::CDummyObject(CObject *obj)
 	m_level = obj->m_level;
 }
 
+#include <new>
+
 class CDummyObject_ : public CDummyObject
 {
 public:
diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp
index 357d67d7..809ba971 100644
--- a/src/objects/Object.cpp
+++ b/src/objects/Object.cpp
@@ -141,6 +141,8 @@ CObject::CanBeDeleted(void)
 	}
 }
 
+#include <new>
+
 class CObject_ : public CObject
 {
 public:
diff --git a/src/objects/Projectile.cpp b/src/objects/Projectile.cpp
index 0f6542e7..32bc6bdb 100644
--- a/src/objects/Projectile.cpp
+++ b/src/objects/Projectile.cpp
@@ -14,6 +14,8 @@ CProjectile::CProjectile(int32 model) : CObject()
 	ObjectCreatedBy = MISSION_OBJECT;
 }
 
+#include <new>
+
 class CProjectile_ : public CProjectile
 {
 public:
diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp
index bb61e086..2e6166be 100644
--- a/src/peds/CivilianPed.cpp
+++ b/src/peds/CivilianPed.cpp
@@ -377,6 +377,8 @@ CCivilianPed::ProcessControl(void)
 		Avoid();
 }
 
+#include <new>
+
 class CCivilianPed_ : public CCivilianPed
 {
 public:
diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp
index 53ae1747..94acac05 100644
--- a/src/peds/CopPed.cpp
+++ b/src/peds/CopPed.cpp
@@ -7,8 +7,11 @@
 #include "Vehicle.h"
 #include "RpAnimBlend.h"
 #include "General.h"
+#include "ZoneCull.h"
+#include "PathFind.h"
+#include "RoadBlocks.h"
 
-WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400);  }
+WRAPPER void CCopPed::ProcessControl() { EAXJMP(0x4C1400); }
 
 CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
 {
@@ -58,11 +61,16 @@ CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP)
 	m_bIsDisabledCop = false;
 	field_1356 = 0;
 	m_attackTimer = 0;
-	field_1351 = 0;
+	m_bBeatingSuspect = false;
 	m_bZoneDisabledButClose = false;
 	m_bZoneDisabled = false;
 	field_1364 = -1;
 	m_pPointGunAt = nil;
+
+	// VC also initializes in here, but it keeps object
+#ifdef FIX_BUGS
+	m_wRoadblockNode = -1;
+#endif
 }
 
 CCopPed::~CCopPed()
@@ -181,15 +189,15 @@ CCopPed::ClearPursuit(void)
 	}
 }
 
-// TO-DO: m_MaxCops in for loop may be a bug, check it out after CopAI
+// TODO: I don't know why they needed that parameter.
 void
-CCopPed::SetPursuit(bool iMayAlreadyBeInPursuit)
+CCopPed::SetPursuit(bool ignoreCopLimit)
 {
 	CWanted *wanted = FindPlayerPed()->m_pWanted;
 	if (m_bIsInPursuit || !IsPedInControl())
 		return;
 
-	if (wanted->m_CurrentCops < wanted->m_MaxCops || iMayAlreadyBeInPursuit) {
+	if (wanted->m_CurrentCops < wanted->m_MaxCops || ignoreCopLimit) {
 		for (int i = 0; i < wanted->m_MaxCops; ++i) {
 			if (!wanted->m_pCops[i]) {
 				m_bIsInPursuit = true;
@@ -275,6 +283,276 @@ CCopPed::ScanForCrimes(void)
 	}
 }
 
+void
+CCopPed::CopAI(void)
+{
+	CWanted *wanted = FindPlayerPed()->m_pWanted;
+	int wantedLevel = wanted->m_nWantedLevel;
+	CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
+
+	if (wanted->m_bIgnoredByEveryone || wanted->m_bIgnoredByCops) {
+		if (m_nPedState != PED_ARREST_PLAYER)
+			ClearPursuit();
+
+		return;
+	}
+	if (CCullZones::NoPolice() && m_bIsInPursuit && !m_bIsDisabledCop) {
+		if (bHitSomethingLastFrame) {
+			m_bZoneDisabled = true;
+			m_bIsDisabledCop = true;
+#ifdef FIX_BUGS
+			m_wRoadblockNode = -1;
+#else
+			m_wRoadblockNode = 0;
+#endif
+			bKindaStayInSamePlace = true;
+			bIsRunning = false;
+			bNotAllowedToDuck = false;
+			bCrouchWhenShooting = false;
+			SetIdle();
+			ClearObjective();
+			ClearPursuit();
+			m_prevObjective = OBJECTIVE_NONE;
+			m_nLastPedState = PED_NONE;
+			SetAttackTimer(0);
+			if (m_fDistanceToTarget > 15.0f)
+				m_bZoneDisabledButClose = true;
+		}
+	} else if (m_bZoneDisabled && !CCullZones::NoPolice()) {
+		m_bZoneDisabled = false;
+		m_bIsDisabledCop = false;
+		m_bZoneDisabledButClose = false;
+		bKindaStayInSamePlace = false;
+		bCrouchWhenShooting = false;
+		bDuckAndCover = false;
+		ClearPursuit();
+	}
+	if (wantedLevel > 0) {
+		if (!m_bIsDisabledCop) {
+			if (!m_bIsInPursuit || wanted->m_CurrentCops > wanted->m_MaxCops) {
+				CCopPed *copFarthestToTarget = nil;
+				float copFarthestToTargetDist = m_fDistanceToTarget;
+
+				int oldCopNum = wanted->m_CurrentCops;
+				int maxCops = wanted->m_MaxCops;
+				
+				for (int i = 0; i < max(maxCops, oldCopNum); i++) {
+					CCopPed *cop = wanted->m_pCops[i];
+					if (cop && cop->m_fDistanceToTarget > copFarthestToTargetDist) {
+						copFarthestToTargetDist = cop->m_fDistanceToTarget;
+						copFarthestToTarget = wanted->m_pCops[i];
+					}
+				}
+
+				if (m_bIsInPursuit) {
+					if (copFarthestToTarget && oldCopNum > maxCops) {
+						if (copFarthestToTarget == this && m_fDistanceToTarget > 10.0f) {
+							ClearPursuit();
+						} else if(copFarthestToTargetDist > 10.0f)
+							copFarthestToTarget->ClearPursuit();
+					}
+				} else {
+					if (oldCopNum < maxCops) {
+						SetPursuit(true);
+					} else {
+						if (m_fDistanceToTarget <= 10.0f || copFarthestToTarget && m_fDistanceToTarget < copFarthestToTargetDist) {
+							if (copFarthestToTarget && copFarthestToTargetDist > 10.0f)
+								copFarthestToTarget->ClearPursuit();
+
+							SetPursuit(true);
+						}
+					}
+				}
+			} else
+				SetPursuit(false);
+
+			if (!m_bIsInPursuit)
+				return;
+
+			if (wantedLevel > 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED)
+				SetCurrentWeapon(WEAPONTYPE_COLT45);
+			else if (wantedLevel == 1 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !FindPlayerPed()->m_pCurrentPhysSurface) {
+				// i.e. if player is on top of car, cop will still use colt45.
+				SetCurrentWeapon(WEAPONTYPE_UNARMED);
+			}
+
+			if (FindPlayerVehicle()) {
+				if (m_bBeatingSuspect) {
+					--wanted->m_CopsBeatingSuspect;
+					m_bBeatingSuspect = false;
+				}
+				if (m_fDistanceToTarget * FindPlayerSpeed().Magnitude() > 4.0f)
+					ClearPursuit();
+			}
+			return;
+		}
+		float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
+		SetLookFlag(playerOrHisVeh, true);
+		TurnBody();
+		SetCurrentWeapon(WEAPONTYPE_COLT45);
+		if (!bIsDucking) {
+			if (m_attackTimer >= CTimer::GetTimeInMilliseconds()) {
+				if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT && !m_bZoneDisabled) {
+					CVector targetDist = playerOrHisVeh->GetPosition() - GetPosition();
+					if (m_fDistanceToTarget > 30.0f) {
+						CAnimBlendAssociation* crouchShootAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT);
+						if (crouchShootAssoc)
+							crouchShootAssoc->blendDelta = -1000.0f;
+
+						// Target is coming onto us
+						if (DotProduct(playerOrHisVeh->m_vecMoveSpeed, targetDist) > 0.0f) {
+							m_bIsDisabledCop = false;
+							bKindaStayInSamePlace = false;
+							bNotAllowedToDuck = false;
+							bDuckAndCover = false;
+							SetPursuit(false);
+							SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, FindPlayerPed());
+						}
+					} else if (m_fDistanceToTarget < 5.0f
+							&& (!FindPlayerVehicle() || FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr() < sq(1.f/200.f))) {
+						m_bIsDisabledCop = false;
+						bKindaStayInSamePlace = false;
+						bNotAllowedToDuck = false;
+						bDuckAndCover = false;
+					} else {
+						// VC checks for != nil compared to buggy behaviour of III. I check for != -1 here.
+#ifdef VC_PED_PORTS
+						float dotProd;
+						if (m_wRoadblockNode != -1) {
+							CTreadable *roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]];
+							dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), GetPosition() - roadBlockRoad->GetPosition());
+						} else
+							dotProd = -1.0f;
+
+						if(dotProd >= 0.0f) {
+#else
+						
+#ifndef FIX_BUGS
+						float copRoadDotProd, targetRoadDotProd;
+#else
+						float copRoadDotProd = 1.0f, targetRoadDotProd = 1.0f;
+						if (m_wRoadblockNode != -1)
+#endif
+						{
+							CTreadable* roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_wRoadblockNode]];
+							CVector2D roadFwd = roadBlockRoad->GetForward();
+							copRoadDotProd = DotProduct2D(GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
+							targetRoadDotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
+						}
+						// Roadblock may be towards road's fwd or opposite, so check both
+						if ((copRoadDotProd >= 0.0f || targetRoadDotProd >= 0.0f)
+							&& (copRoadDotProd <= 0.0f || targetRoadDotProd <= 0.0f)) {
+#endif
+							bIsPointingGunAt = true;
+						} else {
+							m_bIsDisabledCop = false;
+							bKindaStayInSamePlace = false;
+							bNotAllowedToDuck = false;
+							bCrouchWhenShooting = false;
+							bIsDucking = false;
+							bDuckAndCover = false;
+							SetPursuit(false);
+						}
+					}
+				}
+			} else {
+				if (m_fDistanceToTarget < weaponRange) {
+					CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+					CVector gunPos = weaponInfo->m_vecFireOffset;
+					for (RwFrame *i = GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i))
+						RwV3dTransformPoints((RwV3d*)&gunPos, (RwV3d*)&gunPos, 1, RwFrameGetMatrix(i));
+
+					CColPoint foundCol;
+					CEntity *foundEnt;
+					if (!CWorld::ProcessLineOfSight(gunPos, playerOrHisVeh->GetPosition(), foundCol, foundEnt,
+						false, true, false, false, true, false, false)
+						|| foundEnt && foundEnt == playerOrHisVeh) {
+						m_pPointGunAt = playerOrHisVeh;
+						if (playerOrHisVeh)
+							playerOrHisVeh->RegisterReference((CEntity**) &m_pPointGunAt);
+
+						SetAttack(playerOrHisVeh);
+						SetShootTimer(CGeneral::GetRandomNumberInRange(500, 1000));
+					}
+					SetAttackTimer(CGeneral::GetRandomNumberInRange(100, 300));
+				}
+				SetMoveState(PEDMOVE_STILL);
+			}
+		}
+	} else {
+		if (!m_bIsDisabledCop || m_bZoneDisabled) {
+			if (m_nPedState != PED_AIM_GUN) {
+				if (m_bIsInPursuit)
+					ClearPursuit();
+
+				if (IsPedInControl()) {
+					// Entering the vehicle
+					if (m_pMyVehicle && !bInVehicle) {
+						if (m_pMyVehicle->IsLawEnforcementVehicle()) {
+							if (m_pMyVehicle->pDriver) {
+								if (m_pMyVehicle->pDriver->m_nPedType == PEDTYPE_COP) {
+									if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER)
+										SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_pMyVehicle);
+								} else if (m_pMyVehicle->pDriver->IsPlayer()) {
+									FindPlayerPed()->SetWantedLevelNoDrop(1);
+								}
+							} else if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) {
+								SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+							}
+						} else {
+							m_pMyVehicle = nil;
+							ClearObjective();
+							SetWanderPath(CGeneral::GetRandomNumber() & 7);
+						}
+					}
+#ifdef VC_PED_PORTS
+					else {
+						if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && CharCreatedBy == RANDOM_CHAR) {
+							for (int i = 0; i < m_numNearPeds; i++) {
+								CPed *nearPed = m_nearPeds[i];
+								if (nearPed->CharCreatedBy == RANDOM_CHAR) {
+									if ((nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->IsGangMember())
+										&& nearPed->IsPedInControl()) {
+
+										bool anotherCopChasesHim = false;
+										if (nearPed->m_nPedState == PED_FLEE_ENTITY) {
+											if (nearPed->m_fleeFrom && nearPed->m_fleeFrom->IsPed() &&
+												((CPed*)nearPed->m_fleeFrom)->m_nPedType == PEDTYPE_COP) {
+												anotherCopChasesHim = true;
+											}
+										}
+										if (!anotherCopChasesHim) {
+											SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, nearPed);
+											nearPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, this);
+											nearPed->m_ped_flagE2 = true;
+											return;
+										}
+									}
+								}
+							}
+						}
+					}
+#endif
+				}
+			}
+		} else {
+			if (m_bIsInPursuit && m_nPedState != PED_AIM_GUN)
+				ClearPursuit();
+
+			m_bIsDisabledCop = false;
+			bKindaStayInSamePlace = false;
+			bNotAllowedToDuck = false;
+			bCrouchWhenShooting = false;
+			bIsDucking = false;
+			bDuckAndCover = false;
+			if (m_pMyVehicle)
+				SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+		}
+	}
+}
+
+#include <new>
+
 class CCopPed_ : public CCopPed
 {
 public:
@@ -290,4 +568,5 @@ STARTPATCHES
 	InjectHook(0x4C27D0, &CCopPed::SetPursuit, PATCH_JUMP);
 	InjectHook(0x4C2C90, &CCopPed::ArrestPlayer, PATCH_JUMP);
 	InjectHook(0x4C26A0, &CCopPed::ScanForCrimes, PATCH_JUMP);
+	InjectHook(0x4C1B50, &CCopPed::CopAI, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h
index 7705eb12..142be56a 100644
--- a/src/peds/CopPed.h
+++ b/src/peds/CopPed.h
@@ -17,9 +17,9 @@ public:
 	int8 field_1343;
 	float m_fDistanceToTarget;
 	int8 m_bIsInPursuit;
-	int8 m_bIsDisabledCop;
+	int8 m_bIsDisabledCop; // What disabled cop actually is?
 	int8 field_1350;
-	int8 field_1351;
+	bool m_bBeatingSuspect;
 	int8 m_bZoneDisabledButClose;
 	int8 m_bZoneDisabled;
 	int8 field_1354;
@@ -40,6 +40,7 @@ public:
 	void SetPursuit(bool);
 	void ArrestPlayer(void);
 	void ScanForCrimes(void);
+	void CopAI(void);
 };
 
 static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error");
diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp
index ee559f57..0d27a532 100644
--- a/src/peds/EmergencyPed.cpp
+++ b/src/peds/EmergencyPed.cpp
@@ -413,6 +413,8 @@ CEmergencyPed::MedicAI(void)
 	}
 }
 
+#include <new>
+
 class CEmergencyPed_ : public CEmergencyPed
 {
 public:
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index db6b7ee2..05cac3a7 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -2720,6 +2720,10 @@ CPed::SetObjective(eObjective newObj, void *entity)
 			return;
 	}
 
+#ifdef VC_PED_PORTS
+	SetObjectiveTimer(0);
+	ClearPointGunAt();
+#endif
 	bObjectiveCompleted = false;
 	if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) {
 		if (m_objective != newObj) {
@@ -3444,8 +3448,12 @@ CPed::ClearAll(void)
 	m_fleeFrom = nil;
 	m_fleeTimer = 0;
 	bUsesCollision = true;
+#ifdef VC_PED_PORTS
+	ClearPointGunAt();
+#else
 	ClearAimFlag();
 	ClearLookFlag();
+#endif
 	bIsPointingGunAt = false;
 	bRenderPedInCar = true;
 	bKnockedUpIntoAir = false;
@@ -12169,11 +12177,11 @@ CPed::PlacePedOnDryLand(void)
 	if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false))
 		return false;
 
-	CVector potentialGroundDist = CWorld::ms_testSpherePoint.point - GetPosition();
+	CVector potentialGroundDist = gaTempSphereColPoints[0].point - GetPosition();
 	potentialGroundDist.z = 0.0f;
 	potentialGroundDist.Normalise();
 
-	CVector posToCheck = 0.5f * potentialGroundDist + CWorld::ms_testSpherePoint.point;
+	CVector posToCheck = 0.5f * potentialGroundDist + gaTempSphereColPoints[0].point;
 	posToCheck.z = 3.0f + waterLevel;
 
 	if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, false)) {
@@ -17447,6 +17455,8 @@ CPed::SetExitBoat(CVehicle *boat)
 	CWaterLevel::FreeBoatWakeArray();
 }
 
+#include <new>
+
 class CPed_ : public CPed
 {
 public:
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index c6580d32..49d0183e 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -1414,6 +1414,8 @@ CPlayerPed::ProcessControl(void)
 	}
 }
 
+#include <new>
+
 class CPlayerPed_ : public CPlayerPed
 {
 public:
diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp
index d87764ff..6b674dd3 100644
--- a/src/peds/Population.cpp
+++ b/src/peds/Population.cpp
@@ -576,7 +576,7 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree
 	}
 	// Yeah, float
 	float maxPossiblePedsForArea = (zoneInfo.pedDensity + zoneInfo.carDensity) * playerInfo->m_fRoadDensity * PedDensityMultiplier * CIniFile::PedNumberMultiplier;
-	// maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse);
+	maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse);
 
 	if (ms_nTotalPeds < maxPossiblePedsForArea || addCop) {
 		int decisionThreshold = CGeneral::GetRandomNumberInRange(0, 1000);
diff --git a/src/render/Font.cpp b/src/render/Font.cpp
index 7a16ad03..d7b4b5d8 100644
--- a/src/render/Font.cpp
+++ b/src/render/Font.cpp
@@ -94,7 +94,7 @@ CFont::Initialise(void)
 	SetBackgroundColor(CRGBA(0x80, 0x80, 0x80, 0x80));
 	SetBackGroundOnlyTextOff();
 	SetPropOn();
-	SetFontStyle(0);
+	SetFontStyle(FONT_BANK);
 	SetRightJustifyWrap(0.0f);
 	SetAlphaFade(255.0f);
 	SetDropShadowPosition(0);
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index f0134062..52930067 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -115,47 +115,43 @@ void CHud::Draw()
 		return;
 
 	if (m_Wants_To_Draw_Hud && !TheCamera.m_WideScreenOn) {
-		bool Mode_RunAround = 0;
-		bool Mode_FirstPerson = 0;
+		bool DrawCrossHair = 0;
+		bool DrawCrossHairPC = 0;
 
 		int32 WeaponType = FindPlayerPed()->m_weapons[FindPlayerPed()->m_currentWeapon].m_eWeaponType;
 		int32 Mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
 
-		if (Mode == CCam::MODE_SNIPER || Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_M16_1STPERSON || Mode == CCam::MODE_EDITOR)
-			Mode_FirstPerson = 1;
-		if (Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || Mode == CCam::MODE_SNIPER_RUNABOUT)
-			Mode_RunAround = 1;
+		if (Mode == CCam::MODE_SNIPER || Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_M16_1STPERSON || Mode == CCam::MODE_HELICANNON_1STPERSON)
+			DrawCrossHair = 1;
+		if (Mode == CCam::MODE_M16_1STPERSON_RUNABOUT || Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT || Mode == CCam::MODE_SNIPER_RUNABOUT)
+			DrawCrossHairPC = 1;
 
 		/*
 			Draw Crosshairs
 		*/
-		if (TheCamera.Cams->Using3rdPersonMouseCam() && (!CPad::GetPad(0)->GetLookBehindForPed() || TheCamera.m_bPlayerIsInGarage) || Mode == CCam::MODE_1STPERSON_RUNABOUT) {
+		if (TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam() &&
+		    (!CPad::GetPad(0)->GetLookBehindForPed() || TheCamera.m_bPlayerIsInGarage) || Mode == CCam::MODE_1STPERSON_RUNABOUT) {
 			if (FindPlayerPed() && !FindPlayerPed()->EnteringCar()) {
 				if ((WeaponType >= WEAPONTYPE_COLT45 && WeaponType <= WEAPONTYPE_M16) || WeaponType == WEAPONTYPE_FLAMETHROWER)
-					Mode_RunAround = 1;
+					DrawCrossHairPC = 1;
 			}
 		}
 
-		if (Mode_FirstPerson || Mode_RunAround) {
+		if (DrawCrossHair || DrawCrossHairPC) {
 			RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void *)rwFILTERLINEAR);
 
-			int32 SpriteBrightLikeADiamond = SpriteBrightness + 1;
-			if (SpriteBrightLikeADiamond > 30)
-				SpriteBrightLikeADiamond = 30;
-
-			SpriteBrightness = SpriteBrightLikeADiamond;
+			SpriteBrightness = min(SpriteBrightness+1, 30);
 
 			RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
 
-			float fStep = Sin((CTimer::GetTimeInMilliseconds() & 1023) * 0.0061328127);
+			float fStep = Sin((CTimer::GetTimeInMilliseconds() & 1023)/1024.0f * 6.28f);
 			float fMultBright = SpriteBrightness * 0.03f * (0.25f * fStep + 0.75f);
 			CRect rect;
+			if (DrawCrossHairPC && TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam()) {
 #ifndef ASPECT_RATIO_SCALE
-			if (Mode_RunAround && TheCamera.Cams->Using3rdPersonMouseCam()) {
 				float f3rdX = SCREEN_WIDTH * TheCamera.m_f3rdPersonCHairMultX;
 				float f3rdY = SCREEN_HEIGHT * TheCamera.m_f3rdPersonCHairMultY;
 #else
-			if (Mode_RunAround && TheCamera.Cams->Using3rdPersonMouseCam()) {
 				float f3rdX = (((TheCamera.m_f3rdPersonCHairMultX - 0.5f) / ((CDraw::GetAspectRatio()) / (DEFAULT_ASPECT_RATIO))) + 0.5f) * SCREEN_WIDTH;
 				float f3rdY = SCREEN_HEIGHT * TheCamera.m_f3rdPersonCHairMultY + SCREEN_SCALE_Y(-2.0f);
 #endif
@@ -179,14 +175,14 @@ void CHud::Draw()
 			else {
 				if (Mode == CCam::MODE_M16_1STPERSON ||
 				    Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
-				    Mode == CCam::MODE_EDITOR) {
+				    Mode == CCam::MODE_HELICANNON_1STPERSON) {
 					rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(32.0f);
 					rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(32.0f);
 					rect.right = (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(32.0f);
 					rect.bottom = (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(32.0f);
 					Sprites[HUD_SITEM16].Draw(CRect(rect), CRGBA(255, 255, 255, 255));
 				}
-				else if (Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) {
+				else if (Mode == CCam::MODE_1STPERSON_RUNABOUT) {
 					rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(32.0f * 0.7f);
 					rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(32.0f * 0.7f);
 					rect.right = (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(32.0f * 0.7f);
@@ -194,17 +190,18 @@ void CHud::Draw()
 
 					Sprites[HUD_SITEM16].Draw(CRect(rect), CRGBA(255, 255, 255, 255));
 				}
-				else if (Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_SNIPER_RUNABOUT) {
+				else if (Mode == CCam::MODE_ROCKETLAUNCHER || Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) {
 					RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
 					RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
 					RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
 					RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
 					RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
-					RwRenderStateSet(rwRENDERSTATETEXTURERASTER, gpRocketSightTex->raster);
+					RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRocketSightTex));
 
 					CSprite::RenderOneXLUSprite(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 1.0f, SCREEN_SCALE_X(40.0f), SCREEN_SCALE_Y(40.0f), (100.0f * fMultBright), (200.0f * fMultBright), (100.0f * fMultBright), 255, 1.0f, 255);
 				}
 				else {
+					// Sniper
 					rect.left = (SCREEN_WIDTH / 2) - SCREEN_SCALE_X(210.0f);
 					rect.top = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(210.0f);
 					rect.right = SCREEN_WIDTH / 2;
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index ff9f5755..d7834065 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -645,6 +645,9 @@ CRenderer::ScanWorld(void)
 
 	m_loadingPriority = false;
 	if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+#ifdef FIX_BUGS
+	   TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC ||
+#endif
 	   TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
 		CRect rect;
 		int x1, x2, y1, y2;
@@ -756,6 +759,9 @@ CRenderer::RequestObjectsInFrustum(void)
 	RwV3dTransformPoints((RwV3d*)vectors, (RwV3d*)vectors, 9, cammatrix);
 
 	if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+#ifdef FIX_BUGS
+	   TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_GTACLASSIC ||
+#endif
 	   TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED){
 		CRect rect;
 		int x1, x2, y1, y2;
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index 8c851686..2d5cfae2 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS
 #include "common.h"
 #include "main.h"
 #include "patcher.h"
@@ -61,9 +62,9 @@ do {\
 	MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\
 	save_func(buf, &size);\
 	CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\
-	if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + 4))\
+	if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))\
 		return false;\
-	totalSize += size;\
+	totalSize += buf - work_buff;\
 } while (0)
 
 bool
@@ -74,7 +75,6 @@ GenericSave(int file)
 	uint32 reserved;
 
 	uint32 totalSize;
-	uint32 i;
 	
 	wchar *lastMissionPassed;
 	wchar suffix[6];
@@ -85,13 +85,11 @@ GenericSave(int file)
 	CheckSum = 0;
 	buf = work_buff;
 	reserved = 0;
-	totalSize = 0;
 
 	// Save simple vars
-INITSAVEBUF
 	lastMissionPassed = TheText.Get(CStats::LastMissionPassedName);
 	if (*lastMissionPassed) {
-		AsciiToUnicode("'...", suffix);
+		AsciiToUnicode("...'", suffix);
 		TextCopy(saveName, lastMissionPassed);
 		int len = UnicodeStrlen(saveName);
 		saveName[len] = '\0';
@@ -104,20 +102,20 @@ INITSAVEBUF
 	WriteDataToBufferPointer(buf, saveTime);
 	WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES);
 	WriteDataToBufferPointer(buf, CGame::currLevel);
-	WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.x);
-	WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.y);
-	WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.z);
+	WriteDataToBufferPointer(buf, TheCamera.GetPosition().x);
+	WriteDataToBufferPointer(buf, TheCamera.GetPosition().y);
+	WriteDataToBufferPointer(buf, TheCamera.GetPosition().z);
 	WriteDataToBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute);
 	WriteDataToBufferPointer(buf, CClock::ms_nLastClockTick);
 	WriteDataToBufferPointer(buf, CClock::ms_nGameClockHours);
 	WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes);
 	currPad = CPad::GetPad(0);
 	WriteDataToBufferPointer(buf, currPad->Mode);
-	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, CTimer::GetTimeInMilliseconds());
+	WriteDataToBufferPointer(buf, CTimer::GetTimeScale());
+	WriteDataToBufferPointer(buf, CTimer::GetTimeStep());
+	WriteDataToBufferPointer(buf, CTimer::GetTimeStepNonClipped());
+	WriteDataToBufferPointer(buf, CTimer::GetFrameCounter());
 	WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep);
 	WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate);
 	WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale);
@@ -134,10 +132,8 @@ INITSAVEBUF
 	WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList);
 	WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator);
 	WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator);
-#ifdef VALIDATE_SAVE_SIZE
-	_saveBufCount = buf - work_buff;
-#endif
-VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
+
+	assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
 
 	// Save scripts, block is nested within the same block as simple vars for some reason
 	presize = buf;
@@ -145,9 +141,10 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
 	postsize = buf;
 	CTheScripts::SaveAllScripts(buf, &size);
 	CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);
-	if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + SIZE_OF_SIMPLEVARS + 4))
+	if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))
 		return false;
-	totalSize += size + SIZE_OF_SIMPLEVARS;
+
+	totalSize = buf - work_buff;
 
 	// Save the rest
 	WRITE_BLOCK(CPools::SavePedPool);
@@ -171,8 +168,7 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
 	WRITE_BLOCK(CPedType::Save);
 
 	// Write padding
-	i = 0;
-	do {
+	for (int i = 0; i < 4; i++) {
 		size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4);
 		if (size > sizeof(work_buff))
 			size = sizeof(work_buff);
@@ -181,15 +177,15 @@ VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
 				return false;
 			totalSize += size;
 		}
-		i++;
-	} while (i < 4);
+	}
 	
 	// Write checksum and close
 	CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum));
 	if (CFileMgr::GetErrorReadWrite(file)) {
 		PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
-		if (CloseFile(file))
+		if (!CloseFile(file))
 			PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
+
 		return false;
 	}
 	
diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp
index 2702bd6e..744f5e0d 100644
--- a/src/save/PCSave.cpp
+++ b/src/save/PCSave.cpp
@@ -1,3 +1,4 @@
+#define WITHWINDOWS
 #include "common.h"
 #include "patcher.h"
 #include "FileMgr.h"
@@ -38,7 +39,7 @@ C_PcSave::SaveSlot(int32 slot)
 	if (file != 0) {
 		DoGameSpecificStuffBeforeSave();
 		if (GenericSave(file)) {
-			if (CFileMgr::CloseFile(file) != 0)
+			if (!!CFileMgr::CloseFile(file))
 				nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
 			return true;
 		}
@@ -55,21 +56,21 @@ C_PcSave::PcClassSaveRoutine(int32 file, uint8 *data, uint32 size)
 	CFileMgr::Write(file, (const char*)&size, sizeof(size));
 	if (CFileMgr::GetErrorReadWrite(file)) {
 		nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
-		strncpy(SaveFileNameJustSaved, ValidSaveName, 259);
+		strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
 		return false;
 	}
 
 	CFileMgr::Write(file, (const char*)data, align4bytes(size));
-	CheckSum += ((uint8*)&size)[0];
-	CheckSum += ((uint8*)&size)[1];
-	CheckSum += ((uint8*)&size)[2];
-	CheckSum += ((uint8*)&size)[3];
+	CheckSum += (uint8) size;
+	CheckSum += (uint8) (size >> 8);
+	CheckSum += (uint8) (size >> 16);
+	CheckSum += (uint8) (size >> 24);
 	for (int i = 0; i < align4bytes(size); i++) {
 		CheckSum += *data++;
 	}
 	if (CFileMgr::GetErrorReadWrite(file)) {
 		nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
-		strncpy(SaveFileNameJustSaved, ValidSaveName, 259);
+		strncpy(SaveFileNameJustSaved, ValidSaveName, sizeof(ValidSaveName) - 1);
 		return false;
 	}
 
diff --git a/src/text/Pager.h b/src/text/Pager.h
index 727eeb24..1719e726 100644
--- a/src/text/Pager.h
+++ b/src/text/Pager.h
@@ -1,5 +1,5 @@
 #pragma once
-
+
 struct PagerMessage {
 	wchar *m_pText;
 	uint16 m_nSpeedMs;
@@ -9,20 +9,20 @@ struct PagerMessage {
 	uint32 m_nTimeToChangePosition;
 	int16 field_10;
 	int32 m_nNumber[6];
-};
-
-#define NUMPAGERMESSAGES 8
-
-class CPager
-{
+};
+
+#define NUMPAGERMESSAGES 8
+
+class CPager
+{
 	int16 m_nNumDisplayLetters;
-	PagerMessage m_messages[NUMPAGERMESSAGES];
+	PagerMessage m_messages[NUMPAGERMESSAGES];
 public:
-	void Init();
-	void Process();
-	void Display();
+	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();
+	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/text/Text.cpp b/src/text/Text.cpp
index 40717ed5..8bffa7e1 100644
--- a/src/text/Text.cpp
+++ b/src/text/Text.cpp
@@ -1,92 +1,92 @@
-#include "common.h"
-#include "patcher.h"
-#include "FileMgr.h"
-#include "Frontend.h"
-#include "Messages.h"
-#include "Text.h"
-
-static wchar WideErrorString[25];
-
-CText &TheText = *(CText*)0x941520;
-
-CText::CText(void)
-{
-	encoding = 'e';
-	memset(WideErrorString, 0, sizeof(WideErrorString));
-}
-
-void
-CText::Load(void)
-{
-	uint8 *filedata;
-	char filename[32], type[4];
-	int length;
-	int offset, sectlen;
-
-	Unload();
-	filedata = new uint8[0x40000];
-
-	CFileMgr::SetDir("TEXT");
-	switch(CMenuManager::m_PrefsLanguage){
-	case LANGUAGE_AMERICAN:
-		sprintf(filename, "AMERICAN.GXT");
-		break;
-	case LANGUAGE_FRENCH:
-		sprintf(filename, "FRENCH.GXT");
-		break;
-	case LANGUAGE_GERMAN:
-		sprintf(filename, "GERMAN.GXT");
-		break;
-	case LANGUAGE_ITALIAN:
-		sprintf(filename, "ITALIAN.GXT");
-		break;
-	case LANGUAGE_SPANISH:
-		sprintf(filename, "SPANISH.GXT");
-		break;
-	}
-
-	length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb");
-	CFileMgr::SetDir("");
-
-	offset = 0;
-	while(offset < length){
-		type[0] = filedata[offset++];
-		type[1] = filedata[offset++];
-		type[2] = filedata[offset++];
-		type[3] = filedata[offset++];
-		sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 |
-			(int)filedata[offset+1]<<8 | (int)filedata[offset+0];
-		offset += 4;
-		if(sectlen != 0){
-			if(strncmp(type, "TKEY", 4) == 0)
-				keyArray.Load(sectlen, filedata, &offset);
-			else if(strncmp(type, "TDAT", 4) == 0)
-				data.Load(sectlen, filedata, &offset);
-			else
-				offset += sectlen;
-		}
-	}
-
-	keyArray.Update(data.chars);
-
-	delete[] filedata;
-}
-
-void
-CText::Unload(void)
-{
-	CMessages::ClearAllMessagesDisplayedByGame();
-	data.Unload();
-	keyArray.Unload();
-}
-
-wchar*
-CText::Get(const char *key)
-{
-	return keyArray.Search(key);
-}
-
-wchar UpperCaseTable[128] = {
+#include "common.h"
+#include "patcher.h"
+#include "FileMgr.h"
+#include "Frontend.h"
+#include "Messages.h"
+#include "Text.h"
+
+static wchar WideErrorString[25];
+
+CText &TheText = *(CText*)0x941520;
+
+CText::CText(void)
+{
+	encoding = 'e';
+	memset(WideErrorString, 0, sizeof(WideErrorString));
+}
+
+void
+CText::Load(void)
+{
+	uint8 *filedata;
+	char filename[32], type[4];
+	int length;
+	int offset, sectlen;
+
+	Unload();
+	filedata = new uint8[0x40000];
+
+	CFileMgr::SetDir("TEXT");
+	switch(CMenuManager::m_PrefsLanguage){
+	case LANGUAGE_AMERICAN:
+		sprintf(filename, "AMERICAN.GXT");
+		break;
+	case LANGUAGE_FRENCH:
+		sprintf(filename, "FRENCH.GXT");
+		break;
+	case LANGUAGE_GERMAN:
+		sprintf(filename, "GERMAN.GXT");
+		break;
+	case LANGUAGE_ITALIAN:
+		sprintf(filename, "ITALIAN.GXT");
+		break;
+	case LANGUAGE_SPANISH:
+		sprintf(filename, "SPANISH.GXT");
+		break;
+	}
+
+	length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb");
+	CFileMgr::SetDir("");
+
+	offset = 0;
+	while(offset < length){
+		type[0] = filedata[offset++];
+		type[1] = filedata[offset++];
+		type[2] = filedata[offset++];
+		type[3] = filedata[offset++];
+		sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 |
+			(int)filedata[offset+1]<<8 | (int)filedata[offset+0];
+		offset += 4;
+		if(sectlen != 0){
+			if(strncmp(type, "TKEY", 4) == 0)
+				keyArray.Load(sectlen, filedata, &offset);
+			else if(strncmp(type, "TDAT", 4) == 0)
+				data.Load(sectlen, filedata, &offset);
+			else
+				offset += sectlen;
+		}
+	}
+
+	keyArray.Update(data.chars);
+
+	delete[] filedata;
+}
+
+void
+CText::Unload(void)
+{
+	CMessages::ClearAllMessagesDisplayedByGame();
+	data.Unload();
+	keyArray.Unload();
+}
+
+wchar*
+CText::Get(const char *key)
+{
+	return keyArray.Search(key);
+}
+
+wchar UpperCaseTable[128] = {
 	128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
 	139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
 	150, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
@@ -98,10 +98,10 @@ wchar UpperCaseTable[128] = {
 	216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
 	227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
 	238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
-	249, 250, 251, 252, 253, 254, 255
-};
-
-wchar FrenchUpperCaseTable[128] = {
+	249, 250, 251, 252, 253, 254, 255
+};
+
+wchar FrenchUpperCaseTable[128] = {
 	128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
 	139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
 	150, 65, 65, 65, 65, 132, 133, 69, 69, 69, 69, 73, 73,
@@ -113,11 +113,11 @@ wchar FrenchUpperCaseTable[128] = {
 	220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
 	231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
 	242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
-	253, 254, 255
-};
-
-wchar
-CText::GetUpperCase(wchar c)
+	253, 254, 255
+};
+
+wchar
+CText::GetUpperCase(wchar c)
 {
 	switch (encoding)
 	{
@@ -144,176 +144,176 @@ CText::GetUpperCase(wchar c)
 	default:
 		break;
 	}
-	return c;
-}
-
-void
-CText::UpperCase(wchar *s)
-{
-	while(*s){
-		*s = GetUpperCase(*s);
-		s++;
-	}
-}
-
-
-void
-CKeyArray::Load(uint32 length, uint8 *data, int *offset)
-{
-	uint32 i;
-	uint8 *rawbytes;
-
-	numEntries = length / sizeof(CKeyEntry);
-	entries = new CKeyEntry[numEntries];
-	rawbytes = (uint8*)entries;
-
-	for(i = 0; i < length; i++)
-		rawbytes[i] = data[(*offset)++];
-}
-
-void
-CKeyArray::Unload(void)
-{
-	delete[] entries;
-	entries = nil;
-	numEntries = 0;
-}
-
-void
-CKeyArray::Update(wchar *chars)
-{
-	int i;
-	for(i = 0; i < numEntries; i++)
-		entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value);
-}
-
-CKeyEntry*
-CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high)
-{
-	int mid;
-	int diff;
-
-	if(low > high)
-		return nil;
-
-	mid = (low + high)/2;
-	diff = strcmp(key, entries[mid].key);
-	if(diff == 0)
-		return &entries[mid];
-	if(diff < 0)
-		return BinarySearch(key, entries, low, mid-1);
-	if(diff > 0)
-		return BinarySearch(key, entries, mid+1, high);
-	return nil;
-}
-
-wchar*
-CKeyArray::Search(const char *key)
-{
-	CKeyEntry *found;
-	char errstr[25];
-	int i;
-
-	found = BinarySearch(key, entries, 0, numEntries-1);
-	if(found)
-		return found->value;
-	sprintf(errstr, "%s missing", key);
-	for(i = 0; i < 25; i++)
-		WideErrorString[i] = errstr[i];
-	return WideErrorString;
-}
-
-
-void
-CData::Load(uint32 length, uint8 *data, int *offset)
-{
-	uint32 i;
-	uint8 *rawbytes;
-
-	numChars = length / sizeof(wchar);
-	chars = new wchar[numChars];
-	rawbytes = (uint8*)chars;
-
-	for(i = 0; i < length; i++)
-		rawbytes[i] = data[(*offset)++];
-}
-
-void
-CData::Unload(void)
-{
-	delete[] chars;
-	chars = nil;
-	numChars = 0;
-}
-
-void
-AsciiToUnicode(const char *src, wchar *dst)
-{
-	while((*dst++ = *src++) != '\0');
-}
-
-char*
-UnicodeToAscii(wchar *src)
-{
-	static char aStr[256];
-	int len;
-	for(len = 0; *src != '\0' && len < 256-1; len++, src++)
-		if(*src < 128)
-			aStr[len] = *src;
-		else
-			aStr[len] = '#';
-	aStr[len] = '\0';
-	return aStr;
-}
-
-char*
-UnicodeToAsciiForSaveLoad(wchar *src)
-{
-	static char aStr[256];
-	int len;
-	for(len = 0; *src != '\0' && len < 256-1; len++, src++)
-		if(*src < 256)
-			aStr[len] = *src;
-		else
-			aStr[len] = '#';
-	aStr[len] = '\0';
-	return aStr;
-}
-
-void
-UnicodeStrcpy(wchar *dst, const wchar *src)
-{
-	while((*dst++ = *src++) != '\0');
-}
-
-int
-UnicodeStrlen(const wchar *str)
-{
-	int len;
-	for(len = 0; *str != '\0'; len++, str++);
-	return len;
-}
-
-void
-TextCopy(wchar *dst, const wchar *src)
-{
-	while((*dst++ = *src++) != '\0');
-}
-
-
-STARTPATCHES
-	InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP);
-	InjectHook(0x52C580, &CText::Unload, PATCH_JUMP);
-	InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP);
-	InjectHook(0x52C220, &CText::GetUpperCase, PATCH_JUMP);
-	InjectHook(0x52C2C0, &CText::UpperCase, PATCH_JUMP);
-
-	InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP);
-	InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP);
-	InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP);
-	InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP);
-	InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP);
-
-	InjectHook(0x52C120, &CData::Load, PATCH_JUMP);
-	InjectHook(0x52C200, &CData::Unload, PATCH_JUMP);
-ENDPATCHES
+	return c;
+}
+
+void
+CText::UpperCase(wchar *s)
+{
+	while(*s){
+		*s = GetUpperCase(*s);
+		s++;
+	}
+}
+
+
+void
+CKeyArray::Load(uint32 length, uint8 *data, int *offset)
+{
+	uint32 i;
+	uint8 *rawbytes;
+
+	numEntries = length / sizeof(CKeyEntry);
+	entries = new CKeyEntry[numEntries];
+	rawbytes = (uint8*)entries;
+
+	for(i = 0; i < length; i++)
+		rawbytes[i] = data[(*offset)++];
+}
+
+void
+CKeyArray::Unload(void)
+{
+	delete[] entries;
+	entries = nil;
+	numEntries = 0;
+}
+
+void
+CKeyArray::Update(wchar *chars)
+{
+	int i;
+	for(i = 0; i < numEntries; i++)
+		entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value);
+}
+
+CKeyEntry*
+CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high)
+{
+	int mid;
+	int diff;
+
+	if(low > high)
+		return nil;
+
+	mid = (low + high)/2;
+	diff = strcmp(key, entries[mid].key);
+	if(diff == 0)
+		return &entries[mid];
+	if(diff < 0)
+		return BinarySearch(key, entries, low, mid-1);
+	if(diff > 0)
+		return BinarySearch(key, entries, mid+1, high);
+	return nil;
+}
+
+wchar*
+CKeyArray::Search(const char *key)
+{
+	CKeyEntry *found;
+	char errstr[25];
+	int i;
+
+	found = BinarySearch(key, entries, 0, numEntries-1);
+	if(found)
+		return found->value;
+	sprintf(errstr, "%s missing", key);
+	for(i = 0; i < 25; i++)
+		WideErrorString[i] = errstr[i];
+	return WideErrorString;
+}
+
+
+void
+CData::Load(uint32 length, uint8 *data, int *offset)
+{
+	uint32 i;
+	uint8 *rawbytes;
+
+	numChars = length / sizeof(wchar);
+	chars = new wchar[numChars];
+	rawbytes = (uint8*)chars;
+
+	for(i = 0; i < length; i++)
+		rawbytes[i] = data[(*offset)++];
+}
+
+void
+CData::Unload(void)
+{
+	delete[] chars;
+	chars = nil;
+	numChars = 0;
+}
+
+void
+AsciiToUnicode(const char *src, wchar *dst)
+{
+	while((*dst++ = *src++) != '\0');
+}
+
+char*
+UnicodeToAscii(wchar *src)
+{
+	static char aStr[256];
+	int len;
+	for(len = 0; *src != '\0' && len < 256-1; len++, src++)
+		if(*src < 128)
+			aStr[len] = *src;
+		else
+			aStr[len] = '#';
+	aStr[len] = '\0';
+	return aStr;
+}
+
+char*
+UnicodeToAsciiForSaveLoad(wchar *src)
+{
+	static char aStr[256];
+	int len;
+	for(len = 0; *src != '\0' && len < 256-1; len++, src++)
+		if(*src < 256)
+			aStr[len] = *src;
+		else
+			aStr[len] = '#';
+	aStr[len] = '\0';
+	return aStr;
+}
+
+void
+UnicodeStrcpy(wchar *dst, const wchar *src)
+{
+	while((*dst++ = *src++) != '\0');
+}
+
+int
+UnicodeStrlen(const wchar *str)
+{
+	int len;
+	for(len = 0; *str != '\0'; len++, str++);
+	return len;
+}
+
+void
+TextCopy(wchar *dst, const wchar *src)
+{
+	while((*dst++ = *src++) != '\0');
+}
+
+
+STARTPATCHES
+	InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP);
+	InjectHook(0x52C580, &CText::Unload, PATCH_JUMP);
+	InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP);
+	InjectHook(0x52C220, &CText::GetUpperCase, PATCH_JUMP);
+	InjectHook(0x52C2C0, &CText::UpperCase, PATCH_JUMP);
+
+	InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP);
+	InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP);
+	InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP);
+	InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP);
+	InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP);
+
+	InjectHook(0x52C120, &CData::Load, PATCH_JUMP);
+	InjectHook(0x52C200, &CData::Unload, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index a05a1236..44ff6b6d 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -4483,6 +4483,8 @@ CAutomobile::SetAllTaxiLights(bool set)
 	m_sAllTaxiLights = set;
 }
 
+#include <new>
+
 class CAutomobile_ : public CAutomobile
 {
 public:
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 7dbd7080..6d584017 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -299,6 +299,8 @@ CBoat::FillBoatList()
 	}
 }
 
+#include <new>
+
 class CBoat_ : public CBoat
 {
 public:
diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp
index aab9dd0d..9fc50651 100644
--- a/src/vehicles/Heli.cpp
+++ b/src/vehicles/Heli.cpp
@@ -1034,6 +1034,7 @@ bool CHeli::HasCatalinaBeenShotDown(void) { return CatalinaHasBeenShotDown; }
 
 void CHeli::ActivateHeli(bool activate) { ScriptHeliOn = activate; }
 
+#include <new>
 
 class CHeli_ : public CHeli
 {
diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp
index b4d80581..e44ff996 100644
--- a/src/vehicles/Plane.cpp
+++ b/src/vehicles/Plane.cpp
@@ -964,6 +964,7 @@ bool CPlane::HasCesnaLanded(void) { return CesnaMissionStatus == CESNA_STATUS_LA
 bool CPlane::HasCesnaBeenDestroyed(void) { return CesnaMissionStatus == CESNA_STATUS_DESTROYED; }
 bool CPlane::HasDropOffCesnaBeenShotDown(void) { return DropOffCesnaMissionStatus == CESNA_STATUS_DESTROYED; }
 
+#include <new>
 
 class CPlane_ : public CPlane
 {
diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp
index 1c73ed05..6446e6d1 100644
--- a/src/vehicles/Train.cpp
+++ b/src/vehicles/Train.cpp
@@ -691,6 +691,8 @@ CTrain::UpdateTrains(void)
 	}
 }
 
+#include <new>
+
 class CTrain_ : public CTrain
 {
 public:
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 63c9519f..16e61e5f 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -33,6 +33,7 @@ void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->
 WRAPPER bool CVehicle::ShufflePassengersToMakeSpace(void) { EAXJMP(0x5528A0); }
 // or Weapon.cpp?
 WRAPPER void FireOneInstantHitRound(CVector *shotSource, CVector *shotTarget, int32 damage) { EAXJMP(0x563B00); }
+WRAPPER void CVehicle::InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage) { EAXJMP(0x551950); }
 
 CVehicle::CVehicle(uint8 CreatedBy)
 {
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 8c0825cf..2ca97841 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -266,6 +266,7 @@ public:
 	void ProcessCarAlarm(void);
 	bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
 	bool ShufflePassengersToMakeSpace(void);
+	void InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage);
 
 	bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
 	CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }