From 7bf833785411955c2bcf35ed55e9d206facbc575 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Sun, 24 May 2020 15:14:27 +0200
Subject: [PATCH] CVehicle

---
 src/control/CarCtrl.cpp       |    2 +-
 src/control/RoadBlocks.cpp    |    4 +-
 src/control/RoadBlocks.h      |    2 +-
 src/control/Script.cpp        |    4 +-
 src/control/TrafficLights.cpp |    2 +
 src/core/Camera.cpp           |   12 +
 src/core/Camera.h             |    5 +-
 src/core/Collision.cpp        |    9 +-
 src/core/Collision.h          |    6 +-
 src/core/PlayerInfo.h         |    1 +
 src/core/World.cpp            |   62 +-
 src/core/World.h              |    7 +-
 src/core/re3.cpp              |   10 +-
 src/entities/Entity.cpp       |    2 +-
 src/math/Vector2D.h           |    4 +-
 src/math/math.cpp             |   13 -
 src/modelinfo/ModelIndices.h  |    3 +-
 src/peds/Ped.cpp              |   15 +-
 src/peds/Ped.h                |    3 +-
 src/render/Coronas.cpp        |    6 +-
 src/render/Shadows.cpp        |    8 +-
 src/render/Skidmarks.cpp      |    4 +-
 src/render/SpecialFX.cpp      |    1 +
 src/render/SpecialFX.h        |    2 +
 src/render/Timecycle.cpp      |    2 +-
 src/render/Timecycle.h        |    2 +-
 src/render/Weather.cpp        |    6 +-
 src/vehicles/Automobile.cpp   |   73 +-
 src/vehicles/Automobile.h     |    5 +-
 src/vehicles/Heli.cpp         |   54 +-
 src/vehicles/Vehicle.cpp      | 1481 ++++++++++++++++++++++++++++-----
 src/vehicles/Vehicle.h        |   72 +-
 src/weapons/Weapon.cpp        |    4 +-
 33 files changed, 1448 insertions(+), 438 deletions(-)

diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 073195a4..1004e5de 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -913,7 +913,7 @@ CCarCtrl::RemoveDistantCars()
 		PossiblyRemoveVehicle(pVehicle);
 		if (pVehicle->bCreateRoadBlockPeds){
 			if ((pVehicle->GetPosition() - FindPlayerCentreOfWorld(CWorld::PlayerInFocus)).Magnitude2D() < DISTANCE_TO_SPAWN_ROADBLOCK_PEDS) {
-				CRoadBlocks::GenerateRoadBlockCopsForCar(pVehicle, pVehicle->m_nRoadblockType, pVehicle->m_nRoadblockNode);
+				CRoadBlocks::GenerateRoadBlockCopsForCar(pVehicle, pVehicle->m_nRoadblockType);
 				pVehicle->bCreateRoadBlockPeds = false;
 			}
 		}
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
index 0261cd4a..a26e19f5 100644
--- a/src/control/RoadBlocks.cpp
+++ b/src/control/RoadBlocks.cpp
@@ -47,7 +47,7 @@ CRoadBlocks::Init(void)
 }
 
 void
-CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode)
+CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType)
 {
 	static const CVector vecRoadBlockOffets[6] = { {-1.5, 1.8f, 0.0f}, {-1.5f, -1.8f, 0.0f}, {1.5f, 1.8f, 0.0f},
 	{1.5f, -1.8f, 0.0f}, {-1.5f, 0.0f, 0.0f}, {1.5, 0.0, 0.0} };
@@ -90,7 +90,7 @@ CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType
 		pCopPed->SetIdle();
 		pCopPed->bKindaStayInSamePlace = true;
 		pCopPed->bNotAllowedToDuck = false;
-		pCopPed->m_nRoadblockNode = roadBlockNode;
+//		pCopPed->m_nRoadblockNode = roadBlockNode;
 		pCopPed->bCrouchWhenShooting = roadBlockType != 2;
 		if (pEntityToAttack) {
 			pCopPed->m_pPointGunAt = pEntityToAttack;
diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h
index 439fd6e7..c8469ba5 100644
--- a/src/control/RoadBlocks.h
+++ b/src/control/RoadBlocks.h
@@ -15,6 +15,6 @@ public:
 	static bool InOrOut[NUMROADBLOCKS];
 
 	static void Init(void);
-	static void GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType, int16 roadBlockNode);
+	static void GenerateRoadBlockCopsForCar(CVehicle* pVehicle, int32 roadBlockType);
 	static void GenerateRoadBlocks(void);
 };
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index cf2545c0..abcb29bc 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -10943,10 +10943,10 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command)
 				ScriptParams[1] = 0;
 			else if (ScriptParams[1] == 3)
 				ScriptParams[1] = 1;
-			pVehicle->BurstTyre(ScriptParams[1]); // TODO(MIAMI): second param is true
+			pVehicle->BurstTyre(ScriptParams[1], true);
 		}
 		else {
-			pVehicle->BurstTyre(ScriptParams[1]); // TODO(MIAMI): second param is true
+			pVehicle->BurstTyre(ScriptParams[1], true);
 		}
 		return 0;
 	}
diff --git a/src/control/TrafficLights.cpp b/src/control/TrafficLights.cpp
index 8487847f..54c97d06 100644
--- a/src/control/TrafficLights.cpp
+++ b/src/control/TrafficLights.cpp
@@ -108,6 +108,7 @@ CTrafficLights::DisplayActualLight(CEntity *ent)
 	CBrightLights::RegisterOne(pos1, ent->GetUp(), ent->GetRight(), CVector(0.0f, 0.0f, 0.0f), id + BRIGHTLIGHT_TRAFFIC_GREEN);
 	CBrightLights::RegisterOne(pos2, ent->GetUp(), -ent->GetRight(), CVector(0.0f, 0.0f, 0.0f), id + BRIGHTLIGHT_TRAFFIC_GREEN);
 
+/*
 	static const float top = -0.127f;
 	static const float bot = -0.539f;
 	static const float mid = bot + (top-bot)/3.0f;
@@ -131,6 +132,7 @@ CTrafficLights::DisplayActualLight(CEntity *ent)
 			1.0f, 0.5f,  0.0f, 0.5f,  1.0f, 1.0f,  0.0f, 1.0f,
 			SHINYTEXT_WALK, 255, 255, 255, 60.0f);
 	}
+*/
 }
 
 void
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 3b7bdbaf..f618c652 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -3281,6 +3281,18 @@ CCamera::Find3rdPersonQuickAimPitch(void)
 	return -(DEGTORAD(((0.5f - m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV)) + rot);
 }
 
+bool
+CCamera::Using1stPersonWeaponMode(void)
+{
+	switch(PlayerWeaponMode.Mode)
+	case CCam::MODE_SNIPER:
+	case CCam::MODE_M16_1STPERSON:
+	case CCam::MODE_ROCKETLAUNCHER:
+	case CCam::MODE_HELICANNON_1STPERSON:
+	case CCam::MODE_CAMERA:
+		return true;
+	return false;
+}
 
 
 void
diff --git a/src/core/Camera.h b/src/core/Camera.h
index 135f9d8f..4e90855b 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -91,7 +91,9 @@ public:
 		MODE_M16_1STPERSON_RUNABOUT,
 		MODE_FIGHT_CAM_RUNABOUT,
 		MODE_EDITOR,
-		MODE_HELICANNON_1STPERSON, // vice city leftover
+		MODE_HELICANNON_1STPERSON,
+		MODE_45,
+		MODE_CAMERA,
 	};
 
 	bool    bBelowMinDist; //used for follow ped mode
@@ -625,6 +627,7 @@ public:
 	void UpdateAimingCoors(CVector const &coors);
 	void Find3rdPersonCamTargetVector(float dist, CVector pos, CVector &source, CVector &target);
 	float Find3rdPersonQuickAimPitch(void);
+	bool Using1stPersonWeaponMode(void);
 
 	// Physical camera
 	void SetRwCamera(RwCamera *cam);
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index c29c1d28..d2e08f7c 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -414,8 +414,9 @@ CCollision::TestSphereTriangle(const CColSphere &sphere,
 	return dist < sphere.radius;
 }
 
+//--MIAMI: TODO
 bool
-CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough)
+CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough)
 {
 	static CMatrix matTransform;
 	int i;
@@ -1042,10 +1043,11 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere,
 	return true;
 }
 
+//--MIAMI: TODO
 bool
 CCollision::ProcessLineOfSight(const CColLine &line,
 	const CMatrix &matrix, CColModel &model,
-	CColPoint &point, float &mindist, bool ignoreSeeThrough)
+	CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough)
 {
 	static CMatrix matTransform;
 	int i;
@@ -1081,10 +1083,11 @@ CCollision::ProcessLineOfSight(const CColLine &line,
 	return false;
 }
 
+//--MIAMI: TODO
 bool
 CCollision::ProcessVerticalLine(const CColLine &line,
 	const CMatrix &matrix, CColModel &model,
-	CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly)
+	CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough, CStoredCollPoly *poly)
 {
 	static CStoredCollPoly TempStoredPoly;
 	int i;
diff --git a/src/core/Collision.h b/src/core/Collision.h
index 4b0c2fb9..12af5225 100644
--- a/src/core/Collision.h
+++ b/src/core/Collision.h
@@ -151,7 +151,7 @@ public:
 	static bool TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
 	static bool TestLineSphere(const CColLine &line, const CColSphere &sph);
 	static bool TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
-	static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough);
+	static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough);
 
 	static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq);
 	static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq);
@@ -160,8 +160,8 @@ public:
 	static bool ProcessLineTriangle(const CColLine &line , const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist);
 	static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist);
 	static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq);
-	static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough);
-	static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly);
+	static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough);
+	static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough, CStoredCollPoly *poly);
 	static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists);
 	static bool IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly);
 
diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h
index 119f0b2c..e2e874e6 100644
--- a/src/core/PlayerInfo.h
+++ b/src/core/PlayerInfo.h
@@ -51,6 +51,7 @@ public:
 	int32 field_268;
 	int32 field_272;
 	uint32 m_nHavocLevel;
+	float m_fMediaAttention;
 	bool m_bInfiniteSprint;
 	bool m_bFastReload;
 	bool m_bFireproof;
diff --git a/src/core/World.cpp b/src/core/World.cpp
index 433f9745..06108c5c 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -33,22 +33,24 @@
 
 CColPoint gaTempSphereColPoints[MAX_COLLISION_POINTS];
 
-CPtrList CWorld::ms_bigBuildingsList[4];// = (CPtrList*)0x6FAB60;
-CPtrList CWorld::ms_listMovingEntityPtrs;// = *(CPtrList*)0x8F433C;
-CSector CWorld::ms_aSectors[NUMSECTORS_Y][NUMSECTORS_X];// = (CSector (*)[NUMSECTORS_Y])0x665608;
-uint16 CWorld::ms_nCurrentScanCode;// = *(uint16*)0x95CC64;
+CPtrList CWorld::ms_bigBuildingsList[4];
+CPtrList CWorld::ms_listMovingEntityPtrs;
+CSector CWorld::ms_aSectors[NUMSECTORS_Y][NUMSECTORS_X];
+uint16 CWorld::ms_nCurrentScanCode;
 
-uint8 CWorld::PlayerInFocus;// = *(uint8 *)0x95CD61;
+uint8 CWorld::PlayerInFocus;
 CPlayerInfo CWorld::Players[NUMPLAYERS];
-bool CWorld::bNoMoreCollisionTorque;// = *(bool*)0x95CDCC;
-CEntity *CWorld::pIgnoreEntity;//	= *(CEntity**)0x8F6494;
-bool CWorld::bIncludeDeadPeds;// = *(bool*)0x95CD8F;
-bool CWorld::bSecondShift;// = *(bool*)0x95CD54;
-bool CWorld::bForceProcessControl;// = *(bool*)0x95CD6C;
-bool CWorld::bProcessCutsceneOnly;// = *(bool*)0x95CD8B;
+bool CWorld::bNoMoreCollisionTorque;
+CEntity *CWorld::pIgnoreEntity;
+bool CWorld::bIncludeDeadPeds;
+bool CWorld::bSecondShift;
+bool CWorld::bForceProcessControl;
+bool CWorld::bProcessCutsceneOnly;
 
-bool CWorld::bDoingCarCollisions;// = *(bool*)0x95CD8C;
-bool CWorld::bIncludeCarTyres;// = *(bool*)0x95CDAA;
+bool CWorld::bDoingCarCollisions;
+bool CWorld::bIncludeCarTyres;
+
+CColPoint CWorld::m_aTempColPts[MAX_COLLISION_POINTS];
 
 void
 CWorld::Initialise()
@@ -165,7 +167,7 @@ CWorld::CameraToIgnoreThisObject(CEntity *ent)
 bool
 CWorld::ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity,
                            bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects,
-                           bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
+                           bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects, bool ignoreShootThrough)
 {
 	int x, xstart, xend;
 	int y, ystart, yend;
@@ -184,7 +186,7 @@ CWorld::ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoi
 
 #define LOSARGS                                                                                                        \
 	CColLine(point1, point2), point, dist, entity, checkBuildings, checkVehicles, checkPeds, checkObjects,         \
-	    checkDummies, ignoreSeeThrough, ignoreSomeObjects
+	    checkDummies, ignoreSeeThrough, ignoreSomeObjects, ignoreShootThrough
 
 	if(xstart == xend && ystart == yend) {
 		// Only one sector
@@ -266,7 +268,7 @@ CWorld::ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoi
 bool
 CWorld::ProcessLineOfSightSector(CSector &sector, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity,
                                  bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects,
-                                 bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
+                                 bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects, bool ignoreShootThrough)
 {
 	float mindist = dist;
 	bool deadPeds = !!bIncludeDeadPeds;
@@ -274,39 +276,39 @@ CWorld::ProcessLineOfSightSector(CSector &sector, const CColLine &line, CColPoin
 
 	if(checkBuildings) {
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 	}
 
 	if(checkVehicles) {
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 	}
 
 	if(checkPeds) {
 		if(deadPeds) bIncludeDeadPeds = true;
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 		bIncludeDeadPeds = false;
 	}
 
 	if(checkObjects) {
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity,
-		                             ignoreSeeThrough, ignoreSomeObjects);
+		                             ignoreSeeThrough, ignoreSomeObjects, ignoreShootThrough);
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity,
-		                             ignoreSeeThrough, ignoreSomeObjects);
+		                             ignoreSeeThrough, ignoreSomeObjects, ignoreShootThrough);
 	}
 
 	if(checkDummies) {
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 		ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity,
-		                             ignoreSeeThrough);
+		                             ignoreSeeThrough, false, ignoreShootThrough);
 	}
 
 	bIncludeDeadPeds = deadPeds;
@@ -320,7 +322,7 @@ CWorld::ProcessLineOfSightSector(CSector &sector, const CColLine &line, CColPoin
 
 bool
 CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist,
-                                     CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects)
+                                     CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects, bool ignoreShootThrough)
 {
 	bool deadPeds = false;
 	float mindist = dist;
@@ -347,7 +349,7 @@ CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColP
 				colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
 
 			if(colmodel && CCollision::ProcessLineOfSight(line, e->GetMatrix(), *colmodel, point, dist,
-			                                              ignoreSeeThrough))
+			                                              ignoreSeeThrough, ignoreShootThrough))
 				entity = e;
 		}
 	}
@@ -436,7 +438,7 @@ CWorld::ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CCol
 
 			colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
 			if(CCollision::ProcessVerticalLine(line, e->GetMatrix(), *colmodel, point, dist,
-			                                   ignoreSeeThrough, poly))
+			                                   ignoreSeeThrough, false, poly))
 				entity = e;
 		}
 	}
@@ -637,7 +639,7 @@ CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bo
 
 				colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
 
-				if(CCollision::TestLineOfSight(line, e->GetMatrix(), *colmodel, ignoreSeeThrough))
+				if(CCollision::TestLineOfSight(line, e->GetMatrix(), *colmodel, ignoreSeeThrough, false))
 					return false;
 			}
 		}
diff --git a/src/core/World.h b/src/core/World.h
index 89f05cfd..3da774ba 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -71,6 +71,7 @@ public:
 	static bool bProcessCutsceneOnly;
 	static bool bDoingCarCollisions;
 	static bool bIncludeCarTyres;
+	static CColPoint m_aTempColPts[MAX_COLLISION_POINTS];
 
 	static void Remove(CEntity *entity);
 	static void Add(CEntity *entity);
@@ -90,9 +91,9 @@ public:
 
 	static bool CameraToIgnoreThisObject(CEntity *ent);
 
-	static bool ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
-	static bool ProcessLineOfSightSector(CSector &sector, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
-	static bool ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
+	static bool ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false, bool ignoreShootThrough = false);
+	static bool ProcessLineOfSightSector(CSector &sector, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects, bool ignoreShootThrough);
+	static bool ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects, bool ignoreShootThrough);
 	static bool ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly);
 	static bool ProcessVerticalLineSector(CSector &sector, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly);
 	static bool ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly);
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 8f808b61..a74e5ffa 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -273,7 +273,7 @@ DebugMenuPopulate(void)
 {
 	if(1){
 		static const char *weathers[] = {
-			"Sunny", "Cloudy", "Rainy", "Foggy"
+			"Sunny", "Cloudy", "Rainy", "Foggy", "Extrasunny", "Stormy"
 		};
 		DebugMenuEntry *e;
 		e = DebugMenuAddVar("Time & Weather", "Current Hour", &CClock::GetHoursRef(), nil, 1, 0, 23, nil);
@@ -281,9 +281,9 @@ DebugMenuPopulate(void)
 		e = DebugMenuAddVar("Time & Weather", "Current Minute", &CClock::GetMinutesRef(),
 			[](){ CWeather::InterpolationValue = CClock::GetMinutes()/60.0f; }, 1, 0, 59, nil);
 			DebugMenuEntrySetWrap(e, true);
-		e = DebugMenuAddVar("Time & Weather", "Old Weather", (int16*)&CWeather::OldWeatherType, nil, 1, 0, 3, weathers);
+		e = DebugMenuAddVar("Time & Weather", "Old Weather", (int16*)&CWeather::OldWeatherType, nil, 1, 0, 5, weathers);
 		DebugMenuEntrySetWrap(e, true);
-		e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 3, weathers);
+		e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 5, weathers);
 		DebugMenuEntrySetWrap(e, true);
 		DebugMenuAddVar("Time & Weather", "Wind", (float*)&CWeather::Wind, nil, 0.1f, 0.0f, 1.0f);
 		DebugMenuAddVar("Time & Weather", "Time scale", (float*)&CTimer::GetTimeScale(), nil, 0.1f, 0.0f, 10.0f);
@@ -337,7 +337,11 @@ DebugMenuPopulate(void)
 		DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); });
 		DebugMenuAddCmd("Spawn", "Spawn Cuban", [](){ SpawnCar(MI_CUBAN); });
 		DebugMenuAddCmd("Spawn", "Spawn Voodoo", [](){ SpawnCar(MI_VOODOO); });
+		DebugMenuAddCmd("Spawn", "Spawn Maverick", [](){ SpawnCar(MI_MAVERICK); });
+		DebugMenuAddCmd("Spawn", "Spawn VCN Maverick", [](){ SpawnCar(MI_VCNMAV); });
 		DebugMenuAddCmd("Spawn", "Spawn Sparrow", [](){ SpawnCar(MI_SPARROW); });
+		DebugMenuAddCmd("Spawn", "Spawn Sea Sparrow", [](){ SpawnCar(MI_SEASPAR); });
+		DebugMenuAddCmd("Spawn", "Spawn Hunter", [](){ SpawnCar(MI_HUNTER); });
 		DebugMenuAddCmd("Spawn", "Spawn Rhino", [](){ SpawnCar(MI_RHINO); });
 		DebugMenuAddCmd("Spawn", "Spawn Firetruck", [](){ SpawnCar(MI_FIRETRUCK); });
 		DebugMenuAddCmd("Spawn", "Spawn Predator", [](){ SpawnCar(MI_PREDATOR); });
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index a0c5c484..68486a3c 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -910,7 +910,7 @@ CEntity::ProcessLightsForEntity(void)
 				camDir *= 2.0f/dist;
 				glareDir += camDir;
 				glareDir.Normalise();
-				float camAngle = -DotProduct(glareDir, CTimeCycle::GetSunPosition());
+				float camAngle = -DotProduct(glareDir, CTimeCycle::GetSunDirection());
 				if(camAngle > 0.0f){
 					float intens = Sqrt(camAngle) * CWeather::SunGlare;
 					pos += camDir;
diff --git a/src/math/Vector2D.h b/src/math/Vector2D.h
index 0885a5d2..7bfccae6 100644
--- a/src/math/Vector2D.h
+++ b/src/math/Vector2D.h
@@ -11,9 +11,7 @@ public:
 	float Magnitude(void) const { return Sqrt(x*x + y*y); }
 	float MagnitudeSqr(void) const { return x*x + y*y; }
 
-	void Normalise(void);
-
-	void NormaliseSafe(void) {
+	void Normalise(void) {
 		float sq = MagnitudeSqr();
 		if(sq > 0.0f){
 			float invsqrt = RecipSqrt(sq);
diff --git a/src/math/math.cpp b/src/math/math.cpp
index eeb9d3fa..e11d048c 100644
--- a/src/math/math.cpp
+++ b/src/math/math.cpp
@@ -4,19 +4,6 @@
 
 // TODO: move more stuff into here
 
-void
-CVector2D::Normalise(void)
-{
-	float sq = MagnitudeSqr();
-	assert(sq != 0.0f);	// just be safe here
-	//if(sq > 0.0f){
-		float invsqrt = RecipSqrt(sq);
-		x *= invsqrt;
-		y *= invsqrt;
-	//}else
-	//	x = 1.0f;
-}
-
 void
 CMatrix::SetRotate(float xAngle, float yAngle, float zAngle)
 {
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index 91ba650e..e7285b2f 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -302,7 +302,8 @@ enum
 	MI_TRAIN = -1,
 	MI_DODO = -2,
 
-	MI_NIGHTSTICK = 262,
+	MI_GOLFCLUB = 261,
+	MI_NIGHTSTICK,
 	MI_KNIFE,
 	MI_BASEBALL_BAT,
 	MI_GRENADE = 270,
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 7eb2491b..647ecef6 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -66,7 +66,7 @@
 CPed *gapTempPedList[50];
 uint16 gnNumTempPedList;
 
-CColPoint aTempPedColPts[MAX_COLLISION_POINTS];
+static CColPoint aTempPedColPts[MAX_COLLISION_POINTS];
 
 // TODO(Miami)
 #define AUDIO_NOT_READY
@@ -4558,7 +4558,8 @@ CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPi
 					m_pMyVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKESTRAIGHT;
 					m_pMyVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000;
 				}
-				if (m_pMyVehicle->CanPedExitCar()) {
+// TODO(MIAMI): argument
+				if (m_pMyVehicle->CanPedExitCar(false)) {
 					SetObjective(OBJECTIVE_LEAVE_CAR_AND_DIE, m_pMyVehicle);
 				} else {
 					m_fHealth = 0.0f;
@@ -13372,7 +13373,8 @@ CPed::ProcessObjective(void)
 						} else {
 							bool targetHasVeh = m_pedInObjective->bInVehicle;
 							if (!targetHasVeh
-								|| targetHasVeh && m_pedInObjective->m_pMyVehicle->CanPedExitCar()) {
+// TODO(MIAMI): argument
+								|| targetHasVeh && m_pedInObjective->m_pMyVehicle->CanPedExitCar(false)) {
 								m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0;
 								m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
 								SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle);
@@ -15427,13 +15429,13 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints)
 				}
 				float minDist = 1.0f;
 				belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol,
-					intersectionPoint, minDist, false, &m_collPoly);
+					intersectionPoint, minDist, false, false, &m_collPoly);
 
 				if (collidedWithBoat && bWasStanding && !belowTorsoCollided) {
 					ourLine.p0.z = ourLine.p1.z;
 					ourLine.p1.z = ourLine.p1.z + gravityEffect;
 					belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol,
-						intersectionPoint, minDist, false, &m_collPoly);
+						intersectionPoint, minDist, false, false, &m_collPoly);
 				}
 				if (belowTorsoCollided) {
 #ifndef VC_PED_PORTS
@@ -16151,7 +16153,8 @@ CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode)
 	uint32 optedDoorNode = wantedDoorNode;
 	bool teleportNeeded = false;
 	bool isLow = !!veh->bLowVehicle;
-	if (!veh->CanPedExitCar()) {
+// TODO(MIAMI): argument
+	if (!veh->CanPedExitCar(false)) {
 		if (veh->pDriver && !veh->pDriver->IsPlayer()) {
 			veh->AutoPilot.m_nCruiseSpeed = 0;
 			veh->AutoPilot.m_nCarMission = MISSION_NONE;
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index 776aa1dd..155e6cea 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -447,7 +447,7 @@ public:
 	uint32 bIsDrowning : 1;
 	uint32 bDrownsInWater : 1;
 	//uint32 b156_4
-	//uint32 b156_8
+	uint32 b156_8 : 1;
 	uint32 bIsPlayerFriend : 1;
 #ifdef VC_PED_PORTS
 	uint32 bHeadStuckInCollision : 1;
@@ -864,6 +864,7 @@ public:
 	static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg);
 
 	bool IsPlayer(void);
+	bool IsFemale(void) { return m_nPedType == PEDTYPE_CIVFEMALE || m_nPedType == PEDTYPE_PROSTITUTE; }
 	bool UseGroundColModel(void);
 	bool CanSetPedState(void);
 	bool IsPedInControl(void);
diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp
index 8e832ab1..efe486fe 100644
--- a/src/render/Coronas.cpp
+++ b/src/render/Coronas.cpp
@@ -509,18 +509,18 @@ CCoronas::DoSunAndMoon(void)
 {
 	// yeah, moon is done somewhere else....
 
-	CVector sunCoors = CTimeCycle::GetSunPosition();
+	CVector sunCoors = CTimeCycle::GetSunDirection();
 	sunCoors *= 150.0f;
 	sunCoors += TheCamera.GetPosition();
 
-	if(CTimeCycle::GetSunPosition().z > -0.2f){
+	if(CTimeCycle::GetSunDirection().z > -0.2f){
 		float size = ((CGeneral::GetRandomNumber()&0xFF) * 0.005f + 10.0f) * CTimeCycle::GetSunSize();
 		RegisterCorona(SUN_CORE,
 			CTimeCycle::GetSunCoreRed(), CTimeCycle::GetSunCoreGreen(), CTimeCycle::GetSunCoreBlue(),
 			255, sunCoors, size,
 			999999.88f, TYPE_STAR, FLARE_NONE, REFLECTION_OFF, LOSCHECK_OFF, STREAK_OFF, 0.0f);
 
-		if(CTimeCycle::GetSunPosition().z > 0.0f)
+		if(CTimeCycle::GetSunDirection().z > 0.0f)
 			RegisterCorona(SUN_CORONA,
 				CTimeCycle::GetSunCoronaRed(), CTimeCycle::GetSunCoronaGreen(), CTimeCycle::GetSunCoronaBlue(),
 				255, sunCoors, 25.0f * CTimeCycle::GetSunSize(),
diff --git a/src/render/Shadows.cpp b/src/render/Shadows.cpp
index c512f35c..fac35aeb 100644
--- a/src/render/Shadows.cpp
+++ b/src/render/Shadows.cpp
@@ -643,12 +643,12 @@ CShadows::StoreShadowForPole(CEntity *pPole, float fOffsetX, float fOffsetY, flo
 		PolePos.y += fOffsetX * pPole->GetRight().y + fOffsetY * pPole->GetForward().y;
 		PolePos.z += fOffsetZ;
 
-		PolePos.x += -CTimeCycle::GetSunPosition().x * (fPoleHeight / 2);
-		PolePos.y += -CTimeCycle::GetSunPosition().y * (fPoleHeight / 2);
+		PolePos.x += -CTimeCycle::GetSunDirection().x * (fPoleHeight / 2);
+		PolePos.y += -CTimeCycle::GetSunDirection().y * (fPoleHeight / 2);
 
 		StoreStaticShadow((uintptr)pPole + nID + _TODOCONST(51), SHADOWTYPE_DARK, gpPostShadowTex, &PolePos,
-				-CTimeCycle::GetSunPosition().x * (fPoleHeight / 2),
-				-CTimeCycle::GetSunPosition().y * (fPoleHeight / 2),
+				-CTimeCycle::GetSunDirection().x * (fPoleHeight / 2),
+				-CTimeCycle::GetSunDirection().y * (fPoleHeight / 2),
 				CTimeCycle::GetShadowSideX()    * fPoleWidth,
 				CTimeCycle::GetShadowSideY()    * fPoleWidth,
 				2 * (int32)((pPole->GetUp().z - 0.5f) * CTimeCycle::GetShadowStrength() * 2.0f) / 3,
diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp
index 7f057319..961c38a6 100644
--- a/src/render/Skidmarks.cpp
+++ b/src/render/Skidmarks.cpp
@@ -199,8 +199,8 @@ CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *i
 		aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
 
 		CVector2D dist = aSkidmarks[i].m_pos[aSkidmarks[i].m_last] - aSkidmarks[i].m_pos[aSkidmarks[i].m_last-1];
-		dist.NormaliseSafe();
-		fwd.NormaliseSafe();
+		dist.Normalise();
+		fwd.Normalise();
 		CVector2D right(dist.y, -dist.x);
 		float turn = DotProduct2D(fwd, right);
 		turn = Abs(turn) + 1.0f;
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 7e08fbad..79ae21a5 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -28,6 +28,7 @@ RwImVertexIndex StreakIndexList[12];
 RwIm3DVertex TraceVertices[6];
 RwImVertexIndex TraceIndexList[12];
 
+bool CSpecialFX::bSnapShotActive;
 
 void
 CSpecialFX::Init(void)
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index 2d9f18b1..7bc3750a 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -3,6 +3,8 @@
 class CSpecialFX
 {
 public:
+	static bool bSnapShotActive;
+
 	static void Render(void);
 	static void Update(void);
 	static void Init(void);
diff --git a/src/render/Timecycle.cpp b/src/render/Timecycle.cpp
index c120c003..ab94f874 100644
--- a/src/render/Timecycle.cpp
+++ b/src/render/Timecycle.cpp
@@ -350,7 +350,7 @@ CTimeCycle::Update(void)
 	m_CurrentStoredValue = (m_CurrentStoredValue+1)&0xF;
 
 	float sunAngle = 2*PI*(CClock::GetSeconds()/60.0f + CClock::GetMinutes() + CClock::GetHours()*60)/(24*60);
-	CVector &sunPos = GetSunPosition();
+	CVector &sunPos = GetSunDirection();
 	sunPos.x = Sin(sunAngle);
 	sunPos.y = 1.0f;
 	sunPos.z = 0.2f - Cos(sunAngle);
diff --git a/src/render/Timecycle.h b/src/render/Timecycle.h
index 2d873e6d..60c9e29f 100644
--- a/src/render/Timecycle.h
+++ b/src/render/Timecycle.h
@@ -180,7 +180,7 @@ public:
 
 	static void Initialise(void);
 	static void Update(void);
-	static CVector &GetSunPosition(void) { return m_VectorToSun[m_CurrentStoredValue]; }
+	static CVector &GetSunDirection(void) { return m_VectorToSun[m_CurrentStoredValue]; }
 	static float GetShadowFrontX(void) { return m_fShadowFrontX[m_CurrentStoredValue]; }
 	static float GetShadowFrontY(void) { return m_fShadowFrontY[m_CurrentStoredValue]; }
 	static float GetShadowSideX(void) { return m_fShadowSideX[m_CurrentStoredValue]; }
diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp
index fc3e0d61..324c63ea 100644
--- a/src/render/Weather.cpp
+++ b/src/render/Weather.cpp
@@ -18,6 +18,7 @@
 #include "Vehicle.h"
 #include "World.h"
 #include "ZoneCull.h"
+#include "SpecialFX.h"
 
 int32 CWeather::SoundHandle = -1;
 
@@ -271,9 +272,10 @@ void CWeather::Update(void)
 		SunGlare += InterpolationValue;
 
 	if (SunGlare > 0.0f) {
-		SunGlare *= Min(1.0f, 7.0 * CTimeCycle::GetSunPosition().z);
+		SunGlare *= Min(1.0f, 7.0 * CTimeCycle::GetSunDirection().z);
 		SunGlare = clamp(SunGlare, 0.0f, 1.0f);
-		// TODO(MIAMI): if (CSpecialFX::bSnapShotActive)...
+		if (!CSpecialFX::bSnapShotActive)
+			SunGlare *= (1.0f - (CGeneral::GetRandomNumber()&0x1F)*0.007f);
 	}
 
 	Wind = InterpolationValue * Windiness[NewWeatherType] + (1.0f - InterpolationValue) * Windiness[OldWeatherType];
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index dc406237..364415e9 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -77,6 +77,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
 	SetModelIndex(id);
 
 	pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
+	pFlyingHandling = mod_HandlingManager.GetFlyingPointer((eHandlingId)mi->m_handlingId);
 
 	field_49C = 20.0f;
 	field_4D8 = 0;
@@ -176,7 +177,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
 	m_nNumPassengers = 0;
 
 	m_bombType = CARBOMB_NONE;
-	bHadDriver = false;
+	bDriverLastFrame = false;
 	m_pBombRigger = nil;
 
 	if(m_nDoorLock == CARLOCK_UNLOCKED &&
@@ -272,25 +273,14 @@ CAutomobile::ProcessControl(void)
 	}
 
 	// Process driver
-	if(pDriver){
-		if(!bHadDriver && m_bombType == CARBOMB_ONIGNITIONACTIVE){
-			// If someone enters the car and there is a bomb, detonate
-			m_nBombTimer = 1000;
-			m_pBlowUpEntity = m_pBombRigger;
-			if(m_pBlowUpEntity)
-				m_pBlowUpEntity->RegisterReference((CEntity**)&m_pBlowUpEntity);
-			DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TICK, 1.0f);
-		}
-		bHadDriver = true;
+	if(IsUpsideDown() && CanPedEnterCar()){
+		if(!pDriver->IsPlayer() &&
+		   !(pDriver->m_leader && pDriver->m_leader->bInVehicle) &&
+		   pDriver->CharCreatedBy != MISSION_CHAR)
+			pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+	}
 
-		if(IsUpsideDown() && CanPedEnterCar()){
-			if(!pDriver->IsPlayer() &&
-			   !(pDriver->m_leader && pDriver->m_leader->bInVehicle) &&
-			   pDriver->CharCreatedBy != MISSION_CHAR)
-				pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
-		}
-	}else
-		bHadDriver = false;
+	ActivateBombWhenEntered();
 
 	// Process passengers
 	if(m_nNumPassengers != 0 && IsUpsideDown() && CanPedEnterCar()){
@@ -304,18 +294,7 @@ CAutomobile::ProcessControl(void)
 
 	CRubbish::StirUp(this);
 
-	// blend in clump
-	int clumpAlpha = CVisibilityPlugins::GetClumpAlpha((RpClump*)m_rwObject);
-	if(bFadeOut){
-		clumpAlpha -= 8;
-		if(clumpAlpha < 0)
-			clumpAlpha = 0;
-	}else if(clumpAlpha < 255){
-		clumpAlpha += 16;
-		if(clumpAlpha > 255)
-			clumpAlpha = 255;
-	}
-	CVisibilityPlugins::SetClumpAlpha((RpClump*)m_rwObject, clumpAlpha);
+	UpdateClumpAlpha();
 
 	AutoPilot.m_bSlowedDownBecauseOfCars = false;
 	AutoPilot.m_bSlowedDownBecauseOfPeds = false;
@@ -726,19 +705,8 @@ CAutomobile::ProcessControl(void)
 			traction *= 4.0f;
 
 		if(FindPlayerVehicle() && FindPlayerVehicle() == this){
-			if(CPad::GetPad(0)->WeaponJustDown()){
-				if(m_bombType == CARBOMB_TIMED){
-					m_bombType = CARBOMB_TIMEDACTIVE;
-					m_nBombTimer = 7000;
-					m_pBlowUpEntity = FindPlayerPed();
-					CGarages::TriggerMessage("GA_12", -1, 3000, -1);
-					DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TIMED_ACTIVATED, 1.0f);
-				}else if(m_bombType == CARBOMB_ONIGNITION){
-					m_bombType = CARBOMB_ONIGNITIONACTIVE;
-					CGarages::TriggerMessage("GA_12", -1, 3000, -1);
-					DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_ONIGNITION_ACTIVATED, 1.0f);
-				}
-			}
+			if(CPad::GetPad(0)->WeaponJustDown())
+				ActivateBomb();
 		}else if(strongGrip1 || CVehicle::bCheat3){
 			traction *= 1.2f;
 			acceleration *= 1.4f;
@@ -1934,6 +1902,8 @@ CAutomobile::PreRender(void)
 	}
 
 	CShadows::StoreShadowForCar(this);
+
+	DoSunGlare();
 }
 
 void
@@ -3939,7 +3909,7 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel)
 
 	if(m_aCarNodes[CAR_WHEEL_LM] != nil && m_aCarNodes[CAR_WHEEL_RM] != nil){
 		mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LM]));
-		colModel->spheres[4].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RF);
+		colModel->spheres[4].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_LR);
 		mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RM]));
 		colModel->spheres[5].Set(mi->m_wheelScale, mat.GetPosition(), SURFACE_TIRE, CAR_PIECE_WHEEL_RR);
 		colModel->numSpheres = 6;
@@ -3949,9 +3919,8 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel)
 	return true;
 }
 
-// this probably isn't used in III yet
 void
-CAutomobile::BurstTyre(uint8 wheel)
+CAutomobile::BurstTyre(uint8 wheel, bool applyForces)
 {
 	switch(wheel){
 	case CAR_PIECE_WHEEL_LF: wheel = VEHWHEEL_FRONT_LEFT; break;
@@ -3969,8 +3938,10 @@ CAutomobile::BurstTyre(uint8 wheel)
 			CCarCtrl::SwitchVehicleToRealPhysics(this);
 		}
 
-		ApplyMoveForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f));
-		ApplyTurnForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f), GetForward());
+		if(applyForces){
+			ApplyMoveForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f));
+			ApplyTurnForce(GetRight() * CGeneral::GetRandomNumberInRange(-0.3f, 0.3f), GetForward());
+		}
 	}
 }
 
@@ -4337,7 +4308,7 @@ GetCurrentAtomicObjectCB(RwObject *object, void *data)
 	return object;
 }
 
-CColPoint spherepoints[MAX_COLLISION_POINTS];
+static CColPoint aTempPedColPts[MAX_COLLISION_POINTS];
 
 CObject*
 CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
@@ -4457,7 +4428,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
 
 	if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(),
 			this->GetMatrix(), *this->GetColModel(),
-			spherepoints, nil, nil) > 0)
+			aTempPedColPts, nil, nil) > 0)
 		obj->m_pCollidingEntity = this;
 
 	if(bRenderScorched)
diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h
index e096465e..883177aa 100644
--- a/src/vehicles/Automobile.h
+++ b/src/vehicles/Automobile.h
@@ -83,9 +83,10 @@ public:
 	float m_aWheelRotation[4];
 	float m_aWheelPosition[4];
 	float m_aWheelSpeed[4];
+	float m_fRotorSpeed;
 	uint8 field_4D8;
 	uint8 bTaxiLight : 1;
-	uint8 bHadDriver : 1;		// for bombs
+	//uint8 bHadDriver : 1;		// for bombs
 	uint8 bFixedColour : 1;
 	uint8 bBigWheels : 1;
 	uint8 bWaterTight : 1;	// no damage for non-player peds
@@ -146,7 +147,7 @@ public:
 	void RemoveRefsToVehicle(CEntity *ent);
 	void BlowUpCar(CEntity *ent);
 	bool SetUpWheelColModel(CColModel *colModel);
-	void BurstTyre(uint8 tyre);
+	void BurstTyre(uint8 tyre, bool applyForces);
 	bool IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset);
 	float GetHeightAboveRoad(void);
 	void PlayCarHorn(void);
diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp
index 5cd6488a..1e0a8c27 100644
--- a/src/vehicles/Heli.cpp
+++ b/src/vehicles/Heli.cpp
@@ -558,60 +558,8 @@ CHeli::ProcessControl(void)
 void
 CHeli::PreRender(void)
 {
-	float angle;
-	uint8 i;
-	CColPoint point;
-	CEntity *entity;
-	uint8 r, g, b;
-	float testLowZ = FindPlayerCoors().z - 10.0f;
 	float radius = (GetPosition().z - FindPlayerCoors().z - 10.0f - 1.0f) * 0.3f + 10.0f;
-	int frm = CTimer::GetFrameCounter() & 7;
-
-	i = 0;
-	for(angle = 0.0f; angle < TWOPI; angle += TWOPI/32){
-		CVector pos(radius*Cos(angle), radius*Sin(angle), 0.0f);
-		CVector dir = pos*0.01f;
-		pos += GetPosition();
-
-		if(CWorld::ProcessVerticalLine(pos, testLowZ, point, entity, true, false, false, false, true, false, nil))
-			m_fHeliDustZ[frm] = point.point.z;
-		else
-			m_fHeliDustZ[frm] = -101.0f;
-
-		switch(point.surfaceB){
-		default:
-		case SURFACE_TARMAC:
-			r = 10;
-			g = 10;
-			b = 10;
-			break;
-		case SURFACE_GRASS:
-			r = 10;
-			g = 6;
-			b = 3;
-			break;
-		case SURFACE_DIRT:
-			r = 10;
-			g = 8;
-			b = 7;
-			break;
-		case SURFACE_DIRTTRACK:
-			r = 10;
-			g = 6;
-			b = 3;
-			break;
-		}
-		RwRGBA col = { r, g, b, 32 };
-#ifdef FIX_BUGS
-		pos.z = m_fHeliDustZ[frm];
-#else
-		// What the hell is the point of this?
-		pos.z = m_fHeliDustZ[(i - (i&3))/4];	// advance every 4 iterations, why not just /4?
-#endif
-		if(pos.z > -200.0f && GetPosition().z - pos.z < 20.0f)
-			CParticle::AddParticle(PARTICLE_HELI_DUST, pos, dir, nil, 0.0f, col);
-		i++;
-	}
+	HeliDustGenerate(this, radius, FindPlayerCoors().z, Max(16.0f - 4.0f*CTimer::GetTimeStep(), 2.0f));
 }
 
 void
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index f07b633c..c988bf3d 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -14,11 +14,22 @@
 #include "Lights.h"
 #include "PointLights.h"
 #include "Renderer.h"
+#include "VisibilityPlugins.h"
 #include "DMAudio.h"
 #include "Radar.h"
 #include "Fire.h"
 #include "Darkel.h"
 #include "Streaming.h"
+#include "Camera.h"
+#include "Stats.h"
+#include "Garages.h"
+#include "Wanted.h"
+#include "SurfaceTable.h"
+#include "Particle.h"
+#include "WaterLevel.h"
+#include "TimeCycle.h"
+#include "Weather.h"
+#include "Coronas.h"
 
 bool CVehicle::bWheelsOnlyCheat;
 bool CVehicle::bAllDodosCheat;
@@ -53,8 +64,8 @@ CVehicle::CVehicle(uint8 CreatedBy)
 {
 	int i;
 
-	m_nCurrentGear = 0;
-	m_fChangeGearTime = 0;
+	m_nCurrentGear = 1;
+	m_fChangeGearTime = 0.0f;
 	m_fSteerRatio = 0.0f;
 	m_type = ENTITY_TYPE_VEHICLE;
 	VehicleCreatedBy = CreatedBy;
@@ -106,10 +117,22 @@ CVehicle::CVehicle(uint8 CreatedBy)
 	m_nCarHornDelay = 0;
 	bPartOfConvoy = false;
 	bHeliMinimumTilt = false;
+	bAudioChangingGear = false;
 	bIsDrowning = false;
 	bTyresDontBurst = false;
 	bCreatedAsPoliceVehicle = false;
+	bRestingOnPhysical = false;
 	bParking = false;
+	bCanPark = CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.0f;	// BUG? this makes no sense
+	bIsVan = false;
+	bIsBus = false;
+	bIsBig = false;
+	bLowVehicle = false;
+
+	m_bombType = CARBOMB_NONE;
+	bDriverLastFrame = false;
+	m_pBombRigger = nil;
+
 	m_nSetPieceExtendedRangeTime = 0;
 	m_nAlarmState = 0;
 	m_nDoorLock = CARLOCK_UNLOCKED;
@@ -118,6 +141,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
 	m_audioEntityId = DMAudio.CreateEntity(AUDIOTYPE_PHYSICAL, this);
 	if(m_audioEntityId >= 0)
 		DMAudio.SetEntityStatus(m_audioEntityId, true);
+// TODO(MIAMI):
 	m_nRadioStation = CGeneral::GetRandomNumber() % USERTRACK;
 	m_pCurGroundEntity = nil;
 	m_bRainAudioCounter = 0;
@@ -131,9 +155,6 @@ CVehicle::CVehicle(uint8 CreatedBy)
 	AutoPilot.m_bStayInCurrentLevel = false;
 	AutoPilot.m_bIgnorePathfinding = false;
 	AutoPilot.m_nSwitchDistance = 20;
-
-// TODO(MIAMI)
-	bRestingOnPhysical = false;
 }
 
 CVehicle::~CVehicle()
@@ -198,57 +219,30 @@ CVehicle::RemoveLighting(bool reset)
 	CRenderer::RemoveVehiclePedLights(this, reset);
 }
 
+bool
+CVehicle::IsClearToDriveAway(void)
+{
+	CColPoint point;
+	float length = GetColModel()->boundingBox.GetSize().y;
+	CEntity *ent = nil;
+	CVector front = GetForward() * (length*0.5f + 3.0f);
+	return !CWorld::ProcessLineOfSight(GetPosition() + front, GetPosition(),
+			point, ent, true, true, false, false, false, true, true) ||
+		ent == this;
+}
+
 float
 CVehicle::GetHeightAboveRoad(void)
 {
 	return -1.0f * GetColModel()->boundingBox.min.z;
 }
 
-const float fRCPropFallOff = 3.0f;
-const float fRCAeroThrust = 0.003f;
-const float fRCSideSlipMult = 0.1f;
-const float fRCRudderMult = 0.2f;
-const float fRCYawMult = -0.01f;
-const float fRCRollMult = 0.02f;
-const float fRCRollStabilise = -0.08f;
-const float fRCPitchMult = 0.005f;
-const float fRCTailMult = 0.3f;
-const float fRCFormLiftMult = 0.02f;
-const float fRCAttackLiftMult = 0.25f;
-const CVector vecRCAeroResistance(0.998f, 0.998f, 0.9f);
-
-const float fSeaPropFallOff = 2.3f;
-const float fSeaThrust = 0.002f;
-const float fSeaSideSlipMult = 0.1f;
-const float fSeaRudderMult = 0.01f;
-const float fSeaYawMult = -0.0003f;
-const float fSeaRollMult = 0.0015f;
-const float fSeaRollStabilise = -0.01f;
-const float fSeaPitchMult = 0.0002f;
-const float fSeaTailMult = 0.01f;
-const float fSeaFormLiftMult = 0.012f;
-const float fSeaAttackLiftMult = 0.1f;
-const CVector vecSeaAeroResistance(0.995f, 0.995f, 0.85f);
-
-const float fSpeedResistanceY = 500.0f;
-const float fSpeedResistanceZ = 500.0f;
-
-const CVector vecHeliMoveRes(0.995f, 0.995f, 0.99f);
-const CVector vecRCHeliMoveRes(0.99f, 0.99f, 0.99f);
-const float fThrustVar = 0.3f;
-const float fRotorFallOff = 0.75f;
-const float fStabiliseVar = 0.015f;
-const float fPitchBrake = 10.0f;
-const float fPitchVar = 0.006f;
-const float fRollVar = 0.006f;
-const float fYawVar = -0.001f;
-const CVector vecHeliResistance(0.81f, 0.85f, 0.99f);
-const CVector vecRCHeliResistance(0.92f, 0.92f, 0.998f);
-const float fSpinSpeedRes = 20.0f;
-
 void
 CVehicle::FlyingControl(eFlightModel flightModel)
 {
+	if(pFlyingHandling == nil)
+		return;
+
 	switch(flightModel){
 	case FLIGHT_MODEL_DODO:
 	{
@@ -289,6 +283,8 @@ CVehicle::FlyingControl(eFlightModel flightModel)
 
 
 		m_vecTurnSpeed.y *= Pow(0.9f, CTimer::GetTimeStep());
+
+
 		moveSpeed = m_vecMoveSpeed.MagnitudeSqr();
 		if(moveSpeed > SQR(1.5f))
 			m_vecMoveSpeed *= 1.5f/Sqrt(moveSpeed);
@@ -296,172 +292,199 @@ CVehicle::FlyingControl(eFlightModel flightModel)
 		float turnSpeed = m_vecTurnSpeed.MagnitudeSqr();
 		if(turnSpeed > SQR(0.2f))
 			m_vecTurnSpeed *= 0.2f/Sqrt(turnSpeed);
-	}
 		break;
+	}
 
 	case FLIGHT_MODEL_RCPLANE:
 	case FLIGHT_MODEL_SEAPLANE:
+	case FLIGHT_MODEL_PLANE_UNUSED:
+	case FLIGHT_MODEL_PLANE:
 	{
+		float fSteerLR = CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
+		float fSteerUD = -CPad::GetPad(0)->GetSteeringUpDown() / 128.0f;
+		float fGunUD = Abs(CPad::GetPad(0)->GetCarGunUpDown());
+		if(fGunUD > 1.0f)
+			fSteerUD = -CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
+
+		float fSteerAngle = Atan2(fSteerUD, fSteerLR);
+		float fSteerMult = 1.0f;
+		if(fSteerAngle > -PI/4.0f && fSteerAngle <= PI/4.0f)
+			fSteerMult = 1.0f/Cos(fSteerAngle);
+		else if(fSteerAngle > PI/4.0f && fSteerAngle <= PI*3.0f/4.0f)
+			fSteerMult = 1.0f/Cos(fSteerAngle - HALFPI);
+		else if(fSteerAngle > PI*3.0f/4.0f)
+			fSteerMult = 1.0f/Cos(fSteerAngle - PI);
+		else if(fSteerAngle <= -PI*3.0f/4.0f)
+			fSteerMult = 1.0f/Cos(fSteerAngle + PI);
+		else if(fSteerAngle > -PI*3.0f/4.0f && fSteerAngle < -PI/4.0f)
+			fSteerMult = 1.0f/Cos(fSteerAngle + HALFPI);
+
+		fSteerLR *= fSteerMult;
+		fSteerUD *= -fSteerMult;
+
 		// thrust
 		float fForwSpeed = DotProduct(GetMoveSpeed(), GetForward());
 		CVector vecWidthForward = GetColModel()->boundingBox.min.y * GetForward();
 		float fThrust = (CPad::GetPad(0)->GetAccelerate() - CPad::GetPad(0)->GetBrake()) / 255.0f;
-		if (fForwSpeed > 0.1f || (flightModel == FLIGHT_MODEL_RCPLANE && fForwSpeed > 0.02f))
-			fThrust += 1.0f;
-		else if (fForwSpeed > 0.0f && fThrust < 0.0f)
-			fThrust = 0.0f;
-		float fThrustImpulse;
-		if (flightModel == FLIGHT_MODEL_RCPLANE)
-			fThrustImpulse = (fThrust - fRCPropFallOff * fForwSpeed) * fRCAeroThrust;
+		float fThrustAccel;
+		if(fForwSpeed > 0.0f || fThrust > 0.0f)
+			fThrustAccel = (fThrust - pFlyingHandling->fThrustFallOff * fForwSpeed) * pFlyingHandling->fThrust;
 		else
-			fThrustImpulse = (fThrust - fSeaPropFallOff * fForwSpeed) * fSeaThrust;
-		ApplyMoveForce(fThrustImpulse * GetForward() * m_fMass * CTimer::GetTimeStep());
+			fThrustAccel = Min(fThrust - 8.0f * pFlyingHandling->fThrustFallOff * fForwSpeed, 0.0f) * pFlyingHandling->fThrust;
+		if(flightModel == FLIGHT_MODEL_PLANE_UNUSED)
+			fThrustAccel *= 0.3f;
+		else if(flightModel == FLIGHT_MODEL_PLANE)
+			fThrustAccel *= 0.1f;
+		ApplyMoveForce(fThrustAccel * GetForward() * m_fMass * CTimer::GetTimeStep());
 
 		// left/right
 		float fSideSpeed = -DotProduct(GetMoveSpeed(), GetRight());
-		float fSteerLR = CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
-		float fSideSlipImpulse;
-		if (flightModel == FLIGHT_MODEL_RCPLANE)
-			fSideSlipImpulse = Abs(fSideSpeed) * fSideSpeed * fRCSideSlipMult;
-		else
-			fSideSlipImpulse = Abs(fSideSpeed) * fSideSpeed * fSeaSideSlipMult;
-		ApplyMoveForce(m_fMass * GetRight() * fSideSlipImpulse * CTimer::GetTimeStep());
+		float fSideSlipAccel = pFlyingHandling->fSideSlip * fSideSpeed * Abs(fSideSpeed);
+		ApplyMoveForce(m_fMass * GetRight() * fSideSlipAccel * CTimer::GetTimeStep());
 
-		float fYaw = -DotProduct(CrossProduct(m_vecTurnSpeed + m_vecTurnFriction, vecWidthForward) + m_vecMoveSpeed + m_vecMoveFriction, GetRight());
-		float fYawImpulse;
-		if (flightModel == FLIGHT_MODEL_RCPLANE)
-			fYawImpulse = fRCRudderMult * fYaw * Abs(fYaw) + fRCYawMult * fSteerLR * fForwSpeed;
-		else
-			fYawImpulse = fSeaRudderMult * fYaw * Abs(fYaw) + fSeaYawMult * fSteerLR * fForwSpeed;
-		ApplyTurnForce(fYawImpulse * GetRight() * m_fTurnMass * CTimer::GetTimeStep(), vecWidthForward);
+		float fYaw = -DotProduct(GetSpeed(vecWidthForward), GetRight());
+		float fYawAccel = pFlyingHandling->fYawStab * fYaw * Abs(fYaw) + pFlyingHandling->fYaw * fSteerLR * fForwSpeed;
+		ApplyTurnForce(fYawAccel * GetRight() * m_fTurnMass * CTimer::GetTimeStep(), vecWidthForward);
 
-		float fRollImpulse;
+		float fRollAccel;
 		if (flightModel == FLIGHT_MODEL_RCPLANE) {
 			float fDirectionMultiplier = CPad::GetPad(0)->GetLookRight();
 			if (CPad::GetPad(0)->GetLookLeft())
 				fDirectionMultiplier = -1;
-			fRollImpulse = (0.5f * fDirectionMultiplier + fSteerLR) * fRCRollMult;
+			fRollAccel = (0.5f * fDirectionMultiplier + fSteerLR) * pFlyingHandling->fRoll;
 		}
 		else
-			fRollImpulse = fSteerLR * fSeaRollMult;
-		ApplyTurnForce(GetRight() * fRollImpulse * fForwSpeed * m_fTurnMass * CTimer::GetTimeStep(), GetUp());
+			fRollAccel = fSteerLR * pFlyingHandling->fRoll;
+		ApplyTurnForce(GetRight() * fRollAccel * fForwSpeed * m_fTurnMass * CTimer::GetTimeStep(), GetUp());
 
 		CVector vecFRight = CrossProduct(GetForward(), CVector(0.0f, 0.0f, 1.0f));
 		CVector vecStabilise = (GetUp().z > 0.0f) ? vecFRight : -vecFRight;
 		float fStabiliseDirection = (GetRight().z > 0.0f) ? -1.0f : 1.0f;
-		float fStabiliseImpulse;
-		if (flightModel == FLIGHT_MODEL_RCPLANE)
-			fStabiliseImpulse = fRCRollStabilise * fStabiliseDirection * (1.0f - DotProduct(GetRight(), vecStabilise)) * (1.0f - Abs(GetForward().z));
-		else
-			fStabiliseImpulse = fSeaRollStabilise * fStabiliseDirection * (1.0f - DotProduct(GetRight(), vecStabilise)) * (1.0f - Abs(GetForward().z));
-		ApplyTurnForce(fStabiliseImpulse * m_fTurnMass * GetRight(), GetUp()); // no CTimer::GetTimeStep(), is it right? VC doesn't have it too
+		float fStabiliseSpeed = pFlyingHandling->fRollStab * fStabiliseDirection * (1.0f - DotProduct(GetRight(), vecStabilise)) * (1.0f - Abs(GetForward().z));
+		ApplyTurnForce(fStabiliseSpeed * m_fTurnMass * GetRight(), GetUp()); // no CTimer::GetTimeStep(), is it right?
 
 		// up/down
-		float fTail = -DotProduct(CrossProduct(m_vecTurnSpeed + m_vecTurnFriction, vecWidthForward) + m_vecMoveSpeed + m_vecMoveFriction, GetUp());
-		float fSteerUD = -CPad::GetPad(0)->GetSteeringUpDown() / 128.0f;
-		float fPitchImpulse;
-		if (flightModel == FLIGHT_MODEL_RCPLANE)
-			fPitchImpulse = fRCTailMult * fTail * Abs(fTail) + fRCPitchMult * fSteerUD * fForwSpeed;
-		else
-			fPitchImpulse = fSeaTailMult * fTail * Abs(fTail) + fSeaPitchMult * fSteerUD * fForwSpeed;
-		ApplyTurnForce(fPitchImpulse * m_fTurnMass * GetUp() * CTimer::GetTimeStep(), vecWidthForward);
+		float fTail = -DotProduct(GetSpeed(vecWidthForward), GetUp());
+		float fPitchAccel = pFlyingHandling->fPitchStab * fTail * Abs(fTail) + pFlyingHandling->fPitch * fSteerUD * fForwSpeed;
+		ApplyTurnForce(fPitchAccel * m_fTurnMass * GetUp() * CTimer::GetTimeStep(), vecWidthForward);
 
 		float fLift = -DotProduct(GetMoveSpeed(), GetUp()) / Max(0.01f, GetMoveSpeed().Magnitude());
-		float fLiftImpluse;
-		if (flightModel == FLIGHT_MODEL_RCPLANE)
-			fLiftImpluse = (fRCAttackLiftMult * fLift + fRCFormLiftMult) * fForwSpeed * fForwSpeed;
-		else
-			fLiftImpluse = (fSeaAttackLiftMult * fLift + fSeaFormLiftMult) * fForwSpeed * fForwSpeed;
-		float fLiftForce = fLiftImpluse * m_fMass * CTimer::GetTimeStep();
-		if (GRAVITY * CTimer::GetTimeStep() * m_fMass < fLiftImpluse) {
+		float fLiftAccel = (pFlyingHandling->fAttackLift * fLift + pFlyingHandling->fFormLift) * fForwSpeed * fForwSpeed;
+		float fLiftImpulse = fLiftAccel * m_fMass * CTimer::GetTimeStep();
+		if (GRAVITY * CTimer::GetTimeStep() * m_fMass < fLiftImpulse) {
 			if (flightModel == FLIGHT_MODEL_RCPLANE && GetPosition().z > 50.0f)
-				fLiftForce = CTimer::GetTimeStep() * 0.0072 * m_fMass;
+				fLiftImpulse = CTimer::GetTimeStep() * 0.9f*GRAVITY * m_fMass;
 			else if (flightModel == FLIGHT_MODEL_SEAPLANE && GetPosition().z > 80.0f)
-				fLiftForce = CTimer::GetTimeStep() * 0.0072 * m_fMass;
+				fLiftImpulse = CTimer::GetTimeStep() * 0.9f*GRAVITY * m_fMass;
 		}
-		ApplyMoveForce(fLiftForce * GetUp());
+		ApplyMoveForce(fLiftImpulse * GetUp());
+
 		CVector vecResistance;
-		if (flightModel == FLIGHT_MODEL_RCPLANE)
-			vecResistance = vecRCAeroResistance;
-		else
-			vecResistance = vecSeaAeroResistance;
+		vecResistance = pFlyingHandling->vecTurnRes;
 		float rX = Pow(vecResistance.x, CTimer::GetTimeStep());
 		float rY = Pow(vecResistance.y, CTimer::GetTimeStep());
 		float rZ = Pow(vecResistance.z, CTimer::GetTimeStep());
 		CVector vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix());
 		vecTurnSpeed.x *= rX;
-		float fResistance = vecTurnSpeed.y * (1.0f / (fSpeedResistanceY * SQR(vecTurnSpeed.y) + 1.0f)) * rY - vecTurnSpeed.y;
+		float fResistance = vecTurnSpeed.y * (1.0f / (pFlyingHandling->vecSpeedRes.y * SQR(vecTurnSpeed.y) + 1.0f)) * rY - vecTurnSpeed.y;
 		vecTurnSpeed.z *= rZ;
 		m_vecTurnSpeed = Multiply3x3(GetMatrix(), vecTurnSpeed);
 		ApplyTurnForce(-GetUp() * fResistance * m_fTurnMass, GetRight() + Multiply3x3(GetMatrix(), m_vecCentreOfMass));
+
+
+		float fMoveSpeed = m_vecMoveSpeed.MagnitudeSqr();
+		if(fMoveSpeed > SQR(1.5f))
+			m_vecMoveSpeed *= 1.5f/Sqrt(fMoveSpeed);
+
+		float fTurnSpeed = m_vecTurnSpeed.MagnitudeSqr();
+		if(fTurnSpeed > SQR(0.2f))
+			m_vecTurnSpeed *= 0.2f/Sqrt(fTurnSpeed);
 		break;
 	}
+	case FLIGHT_MODEL_RCHELI:
 	case FLIGHT_MODEL_HELI:
 	{
-		CVector vecMoveResistance;
-		if (GetModelIndex() == MI_SPARROW)
-			vecMoveResistance = vecHeliMoveRes;
-		else
-			vecMoveResistance = vecRCHeliMoveRes;
-		float rmX = Pow(vecMoveResistance.x, CTimer::GetTimeStep());
-		float rmY = Pow(vecMoveResistance.y, CTimer::GetTimeStep());
-		float rmZ = Pow(vecMoveResistance.z, CTimer::GetTimeStep());
-		m_vecMoveSpeed.x *= rmX;
-		m_vecMoveSpeed.y *= rmY;
-		m_vecMoveSpeed.z *= rmZ;
+		float rm = Pow(pFlyingHandling->fMoveRes, CTimer::GetTimeStep());
+		m_vecMoveSpeed *= rm;
 		if (GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE)
 			return;
-		float fThrust;
-		if (bCheat5)
-			fThrust = CPad::GetPad(0)->GetSteeringUpDown() * fThrustVar / 128.0f + 0.95f;
-		else
-			fThrust = fThrustVar * (CPad::GetPad(0)->GetAccelerate() - 2 * CPad::GetPad(0)->GetBrake()) / 255.0f + 0.95f;
-		fThrust -= fRotorFallOff * DotProduct(m_vecMoveSpeed, GetUp());
-#ifdef GTA3_1_1_PATCH
-		if (fThrust > 0.9f && GetPosition().z > 80.0f)
-			fThrust = 0.9f;
-#endif
+		float fUpSpeed = DotProduct(m_vecMoveSpeed, GetUp());
+		float fThrust = (CPad::GetPad(0)->GetAccelerate() - CPad::GetPad(0)->GetBrake()) / 255.0f;
+		if(fThrust < 0.0f)
+			fThrust *= 2.0f;
+		if(flightModel == FLIGHT_MODEL_RCHELI){
+			fThrust = pFlyingHandling->fThrust * fThrust + 0.45f;
+			ApplyMoveForce(GRAVITY * CVector(0.0f, 0.0f, 0.5f) * m_fMass * CTimer::GetTimeStep());
+		}else
+			fThrust = pFlyingHandling->fThrust * fThrust + 0.95f;
+		fThrust -= pFlyingHandling->fThrustFallOff * fUpSpeed;
+		if(flightModel == FLIGHT_MODEL_RCHELI && GetPosition().z > 40.0f)
+			fThrust *= 10.0f/(GetPosition().z - 30.0f);
+		else if(GetPosition().z > 80.0f)
+			fThrust *= 10.0f/(GetPosition().z - 70.0f);
 		ApplyMoveForce(GRAVITY * GetUp() * fThrust * m_fMass * CTimer::GetTimeStep());
 
-		if (GetUp().z > 0.0f)
-			ApplyTurnForce(-CVector(GetUp().x, GetUp().y, 0.0f) * fStabiliseVar * m_fTurnMass * CTimer::GetTimeStep(), GetUp());
+		if (GetUp().z > 0.0f){
+			float upRight = clamp(GetRight().z, -pFlyingHandling->fFormLift, pFlyingHandling->fFormLift);
+			float upImpulseRight = -upRight * pFlyingHandling->fAttackLift * m_fTurnMass * CTimer::GetTimeStep();
+			ApplyTurnForce(upImpulseRight * GetUp(), GetRight());
+
+			float upFwd = clamp(GetForward().z, -pFlyingHandling->fFormLift, pFlyingHandling->fFormLift);
+			float upImpulseFwd = -upFwd * pFlyingHandling->fAttackLift * m_fTurnMass * CTimer::GetTimeStep();
+			ApplyTurnForce(upImpulseFwd * GetUp(), GetForward());
+		}else{
+			float upRight = GetRight().z < 0.0f ? -pFlyingHandling->fFormLift : pFlyingHandling->fFormLift;
+			float upImpulseRight = -upRight * pFlyingHandling->fAttackLift * m_fTurnMass * CTimer::GetTimeStep();
+			ApplyTurnForce(upImpulseRight * GetUp(), GetRight());
+
+			float upFwd = GetForward().z < 0.0f ? -pFlyingHandling->fFormLift : pFlyingHandling->fFormLift;
+			float upImpulseFwd = -upFwd * pFlyingHandling->fAttackLift * m_fTurnMass * CTimer::GetTimeStep();
+			ApplyTurnForce(upImpulseFwd * GetUp(), GetForward());
+		}
 
 		float fRoll, fPitch, fYaw;
 		if (bCheat5) {
-			fPitch = CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
-			fRoll = -CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
-			fYaw = CPad::GetPad(0)->GetCarGunLeftRight() / 128.0f;
-		}
-		else {
 			fPitch = CPad::GetPad(0)->GetSteeringUpDown() / 128.0f;
+			fRoll = CPad::GetPad(0)->GetLookLeft();
+			if (CPad::GetPad(0)->GetLookRight())
+				fRoll = -1.0f;
+			fYaw = CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
+		} else {
+			fPitch = CPad::GetPad(0)->GetSteeringUpDown() / 128.0f;
+			fRoll = -CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
 			fYaw = CPad::GetPad(0)->GetLookRight();
 			if (CPad::GetPad(0)->GetLookLeft())
 				fYaw = -1.0f;
-			fRoll = -CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
+			if(Abs(CPad::GetPad(0)->GetCarGunLeftRight()) > 1.0f)
+				fYaw = CPad::GetPad(0)->GetCarGunLeftRight() / 128.0f;
 		}
+		if(Abs(CPad::GetPad(0)->GetCarGunUpDown()) > 1.0f)
+			fPitch = -CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
 		if (CPad::GetPad(0)->GetHorn()) {
 			fYaw = 0.0f;
-			fPitch = clamp(10.0f * DotProduct(m_vecMoveSpeed, GetUp()), -200.0f, 1.3f);
-			fRoll = clamp(10.0f * DotProduct(m_vecMoveSpeed, GetRight()), -200.0f, 1.3f);
+			fPitch = clamp(pFlyingHandling->fPitchStab * DotProduct(m_vecMoveSpeed, GetForward()), -200.0f, 1.3f);
+			fRoll = clamp(pFlyingHandling->fRollStab * DotProduct(m_vecMoveSpeed, GetRight()), -200.0f, 1.3f);
 		}
-		ApplyTurnForce(fPitch * GetUp() * fPitchVar * m_fTurnMass * CTimer::GetTimeStep(), GetForward());
-		ApplyTurnForce(fRoll * GetUp() * fRollVar * m_fTurnMass * CTimer::GetTimeStep(), GetRight());
-		ApplyTurnForce(fYaw * GetForward() * fYawVar * m_fTurnMass * CTimer::GetTimeStep(), GetRight());
+		ApplyTurnForce(fPitch * GetUp() * pFlyingHandling->fPitch * m_fTurnMass * CTimer::GetTimeStep(), GetForward());
+		ApplyTurnForce(fRoll * GetUp() * pFlyingHandling->fRoll * m_fTurnMass * CTimer::GetTimeStep(), GetRight());
 
-		CVector vecResistance;
-		if (GetModelIndex() == MI_SPARROW)
-			vecResistance = vecHeliResistance;
-		else
-			vecResistance = vecRCHeliResistance;
-		float rX = Pow(vecResistance.x, CTimer::GetTimeStep());
-		float rY = Pow(vecResistance.y, CTimer::GetTimeStep());
-		float rZ = Pow(vecResistance.z, CTimer::GetTimeStep());
+		float fSideSpeed = -DotProduct(GetMoveSpeed(), GetRight());
+		float fSideSlipAccel = pFlyingHandling->fSideSlip * fSideSpeed * Abs(fSideSpeed);
+		ApplyMoveForce(m_fMass * GetRight() * fSideSlipAccel * CTimer::GetTimeStep());
+		float fYawAccel = pFlyingHandling->fYawStab * fSideSpeed * Abs(fSideSpeed) + pFlyingHandling->fYaw * fYaw;
+		ApplyTurnForce(fYawAccel * GetRight() * m_fTurnMass * CTimer::GetTimeStep(), -GetForward());
+
+		ApplyTurnForce(fYaw * GetForward() * pFlyingHandling->fYaw * m_fTurnMass * CTimer::GetTimeStep(), GetRight());
+
+		float rX = Pow(pFlyingHandling->vecTurnRes.x, CTimer::GetTimeStep());
+		float rY = Pow(pFlyingHandling->vecTurnRes.y, CTimer::GetTimeStep());
+		float rZ = Pow(pFlyingHandling->vecTurnRes.z, CTimer::GetTimeStep());
 		CVector vecTurnSpeed = Multiply3x3(m_vecTurnSpeed, GetMatrix());
-		float fResistanceMultiplier = Pow(1.0f / (fSpinSpeedRes * SQR(vecTurnSpeed.z) + 1.0f), CTimer::GetTimeStep());
+		float fResistanceMultiplier = Pow(1.0f / (pFlyingHandling->vecSpeedRes.z * SQR(vecTurnSpeed.z) + 1.0f) * rZ, CTimer::GetTimeStep());
 		float fResistance = vecTurnSpeed.z * fResistanceMultiplier - vecTurnSpeed.z;
 		vecTurnSpeed.x *= rX;
 		vecTurnSpeed.y *= rY;
-		vecTurnSpeed.z *= rZ;
+		vecTurnSpeed.z *= fResistanceMultiplier;
 		m_vecTurnSpeed = Multiply3x3(GetMatrix(), vecTurnSpeed);
 		ApplyTurnForce(-GetRight() * fResistance * m_fTurnMass, GetForward() + Multiply3x3(GetMatrix(), m_vecCentreOfMass));
 		break;
@@ -469,6 +492,228 @@ CVehicle::FlyingControl(eFlightModel flightModel)
 	}
 }
 
+static CColModel rotorColModel;
+static CColSphere rotorColSphere;
+float ROTOR_SEMI_THICKNESS = 0.05f;
+float ROTOR_TURN_SPEED = 0.2f;
+float ROTOR_DISGUARD_MULT = 0.3f;
+float ROTOR_COL_ELASTICITY = 1.0f;
+float ROTOR_COL_TURNMULT = -0.001f;
+float ROTOR_DEFAULT_DAMAGE = 100.0f;
+
+bool
+CVehicle::DoBladeCollision(CVector pos, CMatrix &matrix, int16 rotorType, float radius, float damageMult)
+{
+	CVector max(radius, radius, radius);
+	CVector min(-radius, -radius, -radius);
+
+	switch(rotorType){
+	case ROTOR_TOP:
+	case ROTOR_BOTTOM:
+		min.z = -ROTOR_SEMI_THICKNESS;
+		max.z = ROTOR_SEMI_THICKNESS;
+		break;
+	case ROTOR_FRONT:
+	case ROTOR_BACK:
+		min.y = -ROTOR_SEMI_THICKNESS;
+		max.y = ROTOR_SEMI_THICKNESS;
+		break;
+	case ROTOR_RIGHT:
+	case ROTOR_LEFT:
+		min.x = -ROTOR_SEMI_THICKNESS;
+		max.x = ROTOR_SEMI_THICKNESS;
+		break;
+	}
+
+	min += pos;
+	max += pos;
+	rotorColModel.boundingBox.Set(min, max);
+	rotorColModel.boundingSphere.Set(radius, pos);
+	rotorColSphere.Set(radius, pos, 0, 0);
+	rotorColModel.spheres = &rotorColSphere;
+	rotorColModel.numSpheres = 1;
+
+	pos = matrix * pos;
+	bool hadCollision;
+	int minX = CWorld::GetSectorIndexX(pos.x - radius);
+	if(minX <= 0) minX = 0;
+
+	int minY = CWorld::GetSectorIndexY(pos.y - radius);
+	if(minY <= 0) minY = 0;
+
+	int maxX = CWorld::GetSectorIndexX(pos.x + radius);
+#ifdef FIX_BUGS
+	if(maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
+#else
+	if(maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
+#endif
+
+	int maxY = CWorld::GetSectorIndexY(pos.y + radius);
+#ifdef FIX_BUGS
+	if(maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
+#else
+	if(maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y;
+#endif
+
+	CWorld::AdvanceCurrentScanCode();
+	for(int curY = minY; curY <= maxY; curY++) {
+		for(int curX = minX; curX <= maxX; curX++) {
+			CSector *sector = CWorld::GetSector(curX, curY);
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], rotorColModel, matrix, rotorType, damageMult))
+				hadCollision = true;
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], rotorColModel, matrix, rotorType, damageMult))
+				hadCollision = true;
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_VEHICLES], rotorColModel, matrix, rotorType, damageMult))
+				hadCollision = true;
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], rotorColModel, matrix, rotorType, damageMult))
+				hadCollision = true;
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_PEDS], rotorColModel, matrix, rotorType, 0.0f))
+				hadCollision = true;
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], rotorColModel, matrix, rotorType, 0.0f))
+				hadCollision = true;
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_OBJECTS], rotorColModel, matrix, rotorType, damageMult))
+				hadCollision = true;
+			if(BladeColSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], rotorColModel, matrix, rotorType, damageMult))
+				hadCollision = true;
+		}
+	}
+	rotorColModel.spheres = nil;
+	rotorColModel.numSpheres = 0;
+
+	return hadCollision;
+}
+
+bool
+CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &matrix, int16 rotorType, float damageMult)
+{
+	int i;
+	CVector axis;
+	CVector turnSpeed(0.0f, 0.0f, 0.0f);
+	switch(rotorType){
+	case ROTOR_TOP:
+		turnSpeed.z = -ROTOR_TURN_SPEED;
+		axis = -matrix.GetUp();
+		break;
+	case ROTOR_BOTTOM:
+		turnSpeed.z = ROTOR_TURN_SPEED;
+		axis = matrix.GetUp();
+		break;
+
+	case ROTOR_FRONT:
+		turnSpeed.y = -ROTOR_TURN_SPEED;
+		axis = -matrix.GetForward();
+		break;
+	case ROTOR_BACK:
+		turnSpeed.y = ROTOR_TURN_SPEED;
+		axis = matrix.GetForward();
+		break;
+
+	case ROTOR_RIGHT:
+		turnSpeed.x = -ROTOR_TURN_SPEED;
+		axis = -matrix.GetRight();
+		break;
+	case ROTOR_LEFT:
+		turnSpeed.x = ROTOR_TURN_SPEED;
+		axis = matrix.GetRight();
+		break;
+	}
+	turnSpeed = Multiply3x3(matrix, turnSpeed);
+	CVector center = rotorColModel.boundingSphere.center;
+	center = matrix*center;
+
+	for(CPtrNode *node = list.first; node; node = node->next) {
+		CEntity *entity = (CEntity *)node->item;
+		if(entity == (CEntity*)this ||
+		   !entity->bUsesCollision ||
+		   entity->m_scanCode == CWorld::GetCurrentScanCode())
+			continue;
+
+		entity->m_scanCode = CWorld::GetCurrentScanCode();
+
+		int numCollisions;
+		CColModel *entityCol;
+		if(entity->IsPed())
+			entityCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(entity->GetModelIndex()))->AnimatePedColModelSkinned(entity->GetClump());
+		else
+			entityCol = CModelInfo::GetModelInfo(entity->GetModelIndex())->GetColModel();
+		if(entityCol)
+			numCollisions = CCollision::ProcessColModels(matrix, rotorColModel, entity->GetMatrix(), *entityCol,
+				CWorld::m_aTempColPts, nil, nil);
+		else
+			numCollisions = 0;
+
+		if(numCollisions > 0 && entity->IsPed()){
+			CPed *ped = (CPed*)entity;
+			CVector2D dirToRotor = GetPosition() - entity->GetPosition();
+			dirToRotor.Normalise();
+			int localDir = ped->GetLocalDirection(dirToRotor);
+			if(ped->m_attachedTo == nil){
+				ped->bIsStanding = false;
+				ped->ApplyMoveForce(-5.0f*dirToRotor.x, -5.0f*dirToRotor.y, 5.0f);
+			}
+			ped->InflictDamage(this, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, localDir);
+
+			if(CGame::nastyGame && ped->GetIsOnScreen()){
+				for(i = 0; i < 16; i++)
+					CParticle::AddParticle(PARTICLE_BLOOD_SMALL, ped->GetPosition(), CVector(dirToRotor.x, dirToRotor.y, 1.0f) * 0.01f);
+				CParticle::AddParticle(PARTICLE_TEST, ped->GetPosition(), CVector(0.0f, 0.0f, 0.02f), nil, 0.1f);
+				CParticle::AddParticle(PARTICLE_TEST, ped->GetPosition()+CVector(0.0f, 0.0f, 0.2f), CVector(0.0f, 0.0f, -0.01f), nil, 0.1f);
+			}
+		}else if(numCollisions > 0 && entity->GetModelIndex() != MI_MISSILE){
+			float impulse = 0.0f;
+			bool hadCollision = false;
+			float savedElasticity = m_fElasticity;
+			m_fElasticity = ROTOR_COL_ELASTICITY;
+
+			for(i = 0; i < numCollisions; i++){
+				CVector colpos = CWorld::m_aTempColPts[i].point;
+				CVector localColpos = colpos - center;
+				float axisDir = DotProduct(axis, localColpos);
+				float colDir = DotProduct(CWorld::m_aTempColPts[i].normal, localColpos);
+				if(2.0f*ROTOR_SEMI_THICKNESS < Abs(axisDir) &&
+				   ROTOR_DISGUARD_MULT*Abs(colDir) < Abs(axisDir))
+					continue;
+
+				colpos -= axisDir*axis;	// get rid of axis component
+
+				CVector tangentSpeed = CrossProduct(turnSpeed, colpos - center);
+
+				// Particles
+				for(int j = 0; j < 4; j++){
+					CParticle::AddParticle(PARTICLE_SPARK_SMALL, colpos, (tangentSpeed+m_vecMoveSpeed)/2.0f);
+					CParticle::AddParticle(PARTICLE_SPARK, colpos, 0.1f*CWorld::m_aTempColPts[i].normal);
+				}
+
+				// Apply Collision
+				if(IsCar()){
+					CAutomobile *heli = (CAutomobile*)this;
+					if(heli->m_fRotorSpeed > 0.15f){
+						ApplyCollision(CWorld::m_aTempColPts[i], impulse);
+						ApplyTurnForce(m_fTurnMass*ROTOR_COL_TURNMULT*tangentSpeed, colpos - center);
+						heli->m_fRotorSpeed = 0.15f;
+					}else if(heli->m_fRotorSpeed < 0.075f && heli->m_fRotorSpeed > 0.0f)
+						heli->m_fRotorSpeed *= -1.0f;
+				}
+
+				float damageImpulse = damageMult * Max(impulse, ROTOR_DEFAULT_DAMAGE*m_fMass/3000.0f);
+				if(damageImpulse > m_fDamageImpulse)
+					SetDamagedPieceRecord(0, damageImpulse, entity, CWorld::m_aTempColPts[i].normal);
+
+				hadCollision = true;
+			}
+
+			if(hadCollision && !entity->IsPed())
+				DMAudio.ReportCollision(this, entity, SURFACE_BILLBOARD, SURFACE_TARMAC, 50.0f, 0.09f);
+			m_fElasticity = savedElasticity;
+		}
+	}
+	return false;
+}
+
+
+float fBurstSpeedMax = 0.3f;
+float fBurstTyreMod = 0.13f;
+
 void
 CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
 	int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus)
@@ -478,6 +723,10 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
 	static bool bBraking;
 	static bool bDriving;
 
+#ifdef FIX_BUGS
+	bAlreadySkidding = false;
+#endif
+
 	// how much force we want to apply in these axes
 	float fwd = 0.0f;
 	float right = 0.0f;
@@ -509,8 +758,8 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
 #endif
 
 		if(wheelStatus == WHEEL_STATUS_BURST){
-			float fwdspeed = Min(contactSpeedFwd, 0.3f);
-			right += fwdspeed * CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+			float fwdspeed = Min(contactSpeedFwd, fBurstSpeedMax);
+			right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstTyreMod, fBurstTyreMod);
 		}
 	}
 
@@ -535,7 +784,11 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
 
 		if(!bBraking){
 			if(m_fGasPedal < 0.01f){
-				if(GetModelIndex() == MI_RCBANDIT)
+				if(IsBike())
+					brake = 0.6f * mod_HandlingManager.fWheelFriction / (pHandling->fMass + 200.0f);
+				else if(pHandling->fMass < 500.0f)
+					brake = mod_HandlingManager.fWheelFriction / m_fMass;
+				else if(GetModelIndex() == MI_RCBANDIT)
 					brake = 0.2f * mod_HandlingManager.fWheelFriction / m_fMass;
 				else
 					brake = mod_HandlingManager.fWheelFriction / m_fMass;
@@ -559,7 +812,8 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
 		}
 	}
 
-	if(sq(adhesion) < sq(right) + sq(fwd)){
+	float speedSq = sq(right) + sq(fwd);
+	if(sq(adhesion) < speedSq){
 		if(*wheelState != WHEEL_STATE_FIXED){
 			if(bDriving && contactSpeedFwd < 0.2f)
 				*wheelState = WHEEL_STATE_SPINNING;
@@ -567,22 +821,205 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
 				*wheelState = WHEEL_STATE_SKIDDING;
 		}
 
-		float l = Sqrt(sq(right) + sq(fwd));
+		float l = Sqrt(speedSq);
 		float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss;
 		right *= adhesion * tractionLoss / l;
 		fwd *= adhesion * tractionLoss / l;
 	}
 
+	if(fwd != 0.0f || right != 0.0f){
+		CVector totalSpeed = fwd*wheelFwd + right*wheelRight;
+
+		CVector turnDirection = totalSpeed;
+		bool separateTurnForce = false;	// BUG: not initialized on PC
+		if(pHandling->fSuspensionAntidiveMultiplier > 0.0f){
+			if(bBraking){
+				separateTurnForce = true;
+				turnDirection = totalSpeed - pHandling->fSuspensionAntidiveMultiplier*fwd*wheelFwd;
+			}else if(bDriving){
+				separateTurnForce = true;
+				turnDirection = totalSpeed - 0.5f*pHandling->fSuspensionAntidiveMultiplier*fwd*wheelFwd;
+			}
+		}
+
+		CVector direction = totalSpeed;
+
+		float speed = totalSpeed.Magnitude();
+		float turnSpeed;
+		if(separateTurnForce)
+			turnSpeed = turnDirection.Magnitude();
+		else
+			turnSpeed = speed;
+		direction.Normalise();
+		if(separateTurnForce)
+			turnDirection.Normalise();
+		else
+			turnDirection = direction;
+
+		float impulse = speed*m_fMass;
+		float turnImpulse = turnSpeed*GetMass(wheelContactPoint, turnDirection);
+
+		ApplyMoveForce(impulse * direction);
+		ApplyTurnForce(turnImpulse * direction, wheelContactPoint);
+	}
+}
+
+float fBurstBikeSpeedMax = 0.12f;
+float fBurstBikeTyreMod = 0.05f;
+float fTweakBikeWheelTurnForce = 2.0f;
+
+void
+CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
+	int32 wheelsOnGround, float thrust, float brake, float adhesion, float unk, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, eBikeWheelSpecial special, uint16 wheelStatus)
+{
+	// BUG: using statics here is probably a bad idea
+	static bool bAlreadySkidding = false;	// this is never reset
+	static bool bBraking;
+	static bool bDriving;
+	static bool bReversing;
+
+#ifdef FIX_BUGS
+	bAlreadySkidding = false;
+#endif
+
+	// how much force we want to apply in these axes
+	float fwd = 0.0f;
+	float right = 0.0f;
+
+	bBraking = brake != 0.0f;
+	if(bBraking)
+		thrust = 0.0f;
+	bDriving = thrust != 0.0f;
+	bReversing = thrust < 0.0f;
+
+	float contactSpeedFwd = DotProduct(wheelContactSpeed, wheelFwd);
+	float contactSpeedRight;
+
+	if(*wheelState != WHEEL_STATE_NORMAL)
+		bAlreadySkidding = true;
+	*wheelState = WHEEL_STATE_NORMAL;
+
+	adhesion *= CTimer::GetTimeStep();
+	if(bAlreadySkidding)
+		adhesion *= pHandling->fTractionLoss;
+
+	if(special == BIKE_WHEEL_2 || special == BIKE_WHEEL_3)
+		contactSpeedRight = 0.0f;
+	else
+		contactSpeedRight = DotProduct(wheelContactSpeed, wheelRight);
+
+	// moving sideways
+	if(contactSpeedRight != 0.0f){
+		// exert opposing force
+		right = -contactSpeedRight/wheelsOnGround;
+#ifdef FIX_BUGS
+		// contactSpeedRight is independent of framerate but right has timestep as a factor
+		// so we probably have to fix this
+		right *= CTimer::GetTimeStepFix();
+#endif
+
+		if(wheelStatus == WHEEL_STATUS_BURST){
+			float fwdspeed = Min(contactSpeedFwd, fBurstBikeSpeedMax);
+			right += fwdspeed * CGeneral::GetRandomNumberInRange(-fBurstBikeTyreMod, fBurstBikeTyreMod);
+		}
+	}
+
+	if(bDriving){
+		fwd = thrust;
+
+		// limit sideways force (why?)
+		if(right > 0.0f){
+			if(right > adhesion)
+				right = adhesion;
+		}else{
+			if(right < -adhesion)
+				right = -adhesion;
+		}
+	}else if(contactSpeedFwd != 0.0f){
+		fwd = -contactSpeedFwd/wheelsOnGround;
+#ifdef FIX_BUGS
+		// contactSpeedFwd is independent of framerate but fwd has timestep as a factor
+		// so we probably have to fix this
+		fwd *= CTimer::GetTimeStepFix();
+#endif
+
+		if(!bBraking){
+			if(m_fGasPedal < 0.01f){
+				if(IsBike())
+					brake = 0.6f * mod_HandlingManager.fWheelFriction / (pHandling->fMass + 200.0f);
+				else if(pHandling->fMass < 500.0f)
+					brake = mod_HandlingManager.fWheelFriction / m_fMass;
+				else if(GetModelIndex() == MI_RCBANDIT)
+					brake = 0.2f * mod_HandlingManager.fWheelFriction / m_fMass;
+				else
+					brake = mod_HandlingManager.fWheelFriction / m_fMass;
+#ifdef FIX_BUGS
+				brake *= CTimer::GetTimeStepFix();
+#endif
+			}
+		}
+
+		if(brake > adhesion){
+			if(Abs(contactSpeedFwd) > 0.005f)
+				*wheelState = WHEEL_STATE_FIXED;
+		}else {
+			if(fwd > 0.0f){
+				if(fwd > brake)
+					fwd = brake;
+			}else{
+				if(fwd < -brake)
+					fwd = -brake;
+			}
+		}
+	}
+
+	float speedSq = sq(right) + sq(fwd);
+	if(sq(adhesion) < speedSq){
+		if(*wheelState != WHEEL_STATE_FIXED){
+			if(bDriving && contactSpeedFwd < 0.2f)
+				*wheelState = WHEEL_STATE_SPINNING;
+			else
+				*wheelState = WHEEL_STATE_SKIDDING;
+		}
+
+		float l = Sqrt(speedSq);
+		float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss;
+		right *= adhesion * tractionLoss / l;
+		fwd *= adhesion * tractionLoss / l;
+
+		if(unk < 1.0f)
+			right *= unk;
+	}else if(unk < 1.0f){
+		if(!bAlreadySkidding)
+			unk *= pHandling->fTractionLoss;
+		if(sq(adhesion*unk) < speedSq){
+			float l = Sqrt(speedSq);
+			right *= adhesion * unk / l;
+		}
+	}
+
 	if(fwd != 0.0f || right != 0.0f){
 		CVector direction = fwd*wheelFwd + right*wheelRight;
+
 		float speed = direction.Magnitude();
 		direction.Normalise();
 
 		float impulse = speed*m_fMass;
 		float turnImpulse = speed*GetMass(wheelContactPoint, direction);
+		CVector vTurnImpulse = turnImpulse * direction;
+		float turnRight = DotProduct(vTurnImpulse, GetRight());
 
 		ApplyMoveForce(impulse * direction);
-		ApplyTurnForce(turnImpulse * direction, wheelContactPoint);
+
+		float contactRight = DotProduct(wheelContactPoint, GetRight());
+		float contactFwd = DotProduct(wheelContactPoint, GetForward());
+
+		if(wheelId != CARWHEEL_REAR_LEFT ||
+		   !bBraking && !bReversing)
+			ApplyTurnForce((vTurnImpulse - turnRight*GetRight()) * fTweakBikeWheelTurnForce,
+				wheelContactPoint - contactRight*GetRight());
+
+		ApplyTurnForce(turnRight*GetRight(), contactFwd*GetForward());
 	}
 }
 
@@ -604,40 +1041,81 @@ CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVec
 	return angularVelocity * CTimer::GetTimeStep();
 }
 
+int
+CVehicle::FindTyreNearestPoint(float x, float y)
+{
+	CVector pos = CVector(x - GetPosition().x, y - GetPosition().y, 0.0f);
+	float fwd = DotProduct(GetForward(), pos);
+	float right = DotProduct(GetRight(), pos);
+
+	int piece;
+	if(IsBike()){
+		piece = fwd > 0.0f ? CAR_PIECE_WHEEL_LF : CAR_PIECE_WHEEL_LR;
+	}else{
+		piece = fwd > 0.0f ?
+			right > 0.0f ? CAR_PIECE_WHEEL_RF : CAR_PIECE_WHEEL_LF :
+			right > 0.0f ? CAR_PIECE_WHEEL_RR : CAR_PIECE_WHEEL_LR;
+	}
+	return piece - CAR_PIECE_WHEEL_LF;
+}
+
 void
-CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage)
+CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage, CVector pos)
 {
 	if (!bCanBeDamaged)
 		return;
-	if (bOnlyDamagedByPlayer && (damagedBy != FindPlayerPed() && damagedBy != FindPlayerVehicle()))
+	if(GetStatus() == STATUS_PLAYER && CStats::GetPercentageProgress() >= 100.0f)
+		damage *= 0.5f;
+	if (GetStatus() != STATUS_PLAYER && bOnlyDamagedByPlayer && (damagedBy != FindPlayerPed() && damagedBy != FindPlayerVehicle()))
 		return;
+
+	if(damage > 10.0f && (damagedBy == FindPlayerPed() || damagedBy == FindPlayerVehicle()) && GetStatus() != STATUS_WRECKED){
+		CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel += 2;
+		CWorld::Players[CWorld::PlayerInFocus].m_fMediaAttention += 1.0f;
+		CStats::PropertyDestroyed += CGeneral::GetRandomNumberInRange(5, 25);
+	}
+
 	bool bFrightensDriver = false;
 	switch (weaponType) {
 	case WEAPONTYPE_UNARMED:
+	case WEAPONTYPE_BRASSKNUCKLE:
+	case WEAPONTYPE_SCREWDRIVER:
+	case WEAPONTYPE_GOLFCLUB:
+	case WEAPONTYPE_NIGHTSTICK:
+	case WEAPONTYPE_KNIFE:
 	case WEAPONTYPE_BASEBALLBAT:
+	case WEAPONTYPE_HAMMER:
+	case WEAPONTYPE_CLEAVER:
+	case WEAPONTYPE_MACHETE:
+	case WEAPONTYPE_KATANA:
+	case WEAPONTYPE_CHAINSAW:
 		if (bMeleeProof)
 			return;
 		break;
 	case WEAPONTYPE_COLT45:
-	case WEAPONTYPE_UZI:
-	case WEAPONTYPE_TEC9:
-	case WEAPONTYPE_SILENCED_INGRAM:
-	case WEAPONTYPE_MP5:
+	case WEAPONTYPE_PYTHON:
 	case WEAPONTYPE_SHOTGUN:
 	case WEAPONTYPE_SPAS12_SHOTGUN:
 	case WEAPONTYPE_STUBBY_SHOTGUN:
-	case WEAPONTYPE_RUGER:
+	case WEAPONTYPE_TEC9:
+	case WEAPONTYPE_UZI:
+	case WEAPONTYPE_SILENCED_INGRAM:
+	case WEAPONTYPE_MP5:
 	case WEAPONTYPE_M4:
+	case WEAPONTYPE_RUGER:
 	case WEAPONTYPE_SNIPERRIFLE:
+	case WEAPONTYPE_LASERSCOPE:
+	case WEAPONTYPE_M60:
+	case WEAPONTYPE_MINIGUN:
 	case WEAPONTYPE_HELICANNON:
 	case WEAPONTYPE_UZI_DRIVEBY:
 		if (bBulletProof)
 			return;
 		bFrightensDriver = true;
 		break;
-	case WEAPONTYPE_ROCKETLAUNCHER:
-	case WEAPONTYPE_MOLOTOV:
 	case WEAPONTYPE_GRENADE:
+	case WEAPONTYPE_MOLOTOV:
+	case WEAPONTYPE_ROCKET:
 	case WEAPONTYPE_EXPLOSION:
 		if (bExplosionProof)
 			return;
@@ -654,6 +1132,52 @@ CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage
 	default:
 		break;
 	}
+
+	if(bFrightensDriver && GetStatus() == STATUS_PLAYER && m_fHealth < 250.0f)
+		return;
+
+	// Pop tires
+	if(damagedBy && damagedBy->IsPed() && (IsCar() || IsBike())){
+		int accuracy = 0;
+		switch(weaponType){
+		case WEAPONTYPE_COLT45:
+			accuracy = 10;
+			break;
+		case WEAPONTYPE_PYTHON:
+			if(!((CPed*)damagedBy)->IsPlayer())
+				accuracy = 64;
+			break;
+		case WEAPONTYPE_SHOTGUN:
+		case WEAPONTYPE_STUBBY_SHOTGUN:
+		case WEAPONTYPE_M60:
+		case WEAPONTYPE_HELICANNON:
+			accuracy = 25;
+			break;
+		case WEAPONTYPE_TEC9:
+		case WEAPONTYPE_UZI:
+		case WEAPONTYPE_SILENCED_INGRAM:
+		case WEAPONTYPE_MP5:
+		case WEAPONTYPE_UZI_DRIVEBY:
+			accuracy = 15;
+			break;
+		case WEAPONTYPE_M4:
+		case WEAPONTYPE_RUGER:
+			if(!((CPed*)damagedBy)->IsPlayer())
+				accuracy = 15;
+			break;
+		}
+
+		if(((CPed*)damagedBy)->IsPlayer() && (CCamera::m_bUseMouse3rdPerson || TheCamera.Using1stPersonWeaponMode()))
+			accuracy = 0;
+
+		if(accuracy != 0 && !bTyresDontBurst && (CGeneral::GetRandomNumber()&0x7F) < accuracy){
+			if(IsBike())
+				BurstTyre(FindTyreNearestPoint(pos.x, pos.y) + CAR_PIECE_WHEEL_LF, false);
+			else if(GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR)
+				BurstTyre(FindTyreNearestPoint(pos.x, pos.y) + CAR_PIECE_WHEEL_LF, true);
+		}
+	}
+
 	if (m_fHealth > 0.0f) {
 		if (VehicleCreatedBy == RANDOM_VEHICLE && pDriver &&
 			(GetStatus() == STATUS_SIMPLE || GetStatus() == STATUS_PHYSICS) &&
@@ -666,24 +1190,43 @@ CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage
 			}
 		}
 		m_nLastWeaponDamage = weaponType;
+		m_pLastDamageEntity = damagedBy;
 		float oldHealth = m_fHealth;
 		if (m_fHealth > damage) {
 			m_fHealth -= damage;
-			if (VehicleCreatedBy == RANDOM_VEHICLE &&
-				(m_fHealth < DAMAGE_HEALTH_TO_FLEE_ALWAYS ||
-					bFrightensDriver && m_randomSeed > DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE)) {
+			if (VehicleCreatedBy == RANDOM_VEHICLE && !IsBoat()){
 				switch (GetStatus()) {
 				case STATUS_SIMPLE:
 				case STATUS_PHYSICS:
-					if (pDriver) {
-						SetStatus(STATUS_ABANDONED);
-						pDriver->bFleeAfterExitingCar = true;
-						pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
-					}
-					for (int i = 0; i < m_nNumMaxPassengers; i++) {
-						if (pPassengers[i]) {
-							pPassengers[i]->bFleeAfterExitingCar = true;
-							pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+					if(AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_PLOUGH_THROUGH ||
+					   CGeneral::GetRandomNumberInRange(0.0f, 1.0f) > 0.5f && AutoPilot.m_nCarMission == MISSION_CRUISE){
+						// Drive away like a maniac
+						if(pDriver && pDriver->m_objective != OBJECTIVE_LEAVE_VEHICLE){
+							if(AutoPilot.m_nDrivingStyle != DRIVINGSTYLE_PLOUGH_THROUGH)
+								AutoPilot.m_nCruiseSpeed *= 1.5f;
+							AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_PLOUGH_THROUGH;
+						}
+					}else{
+						// Leave vehicle
+						if (pDriver && pDriver->CharCreatedBy != MISSION_CHAR) {
+							SetStatus(STATUS_ABANDONED);
+							pDriver->bFleeAfterExitingCar = true;
+							pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+// TODO(MIAMI):
+//							pDriver->Say(120);
+						}
+						int time = 200;
+						for (int i = 0; i < m_nNumMaxPassengers; i++) {
+							if (pPassengers[i] &&
+							    pPassengers[i]->m_objective != OBJECTIVE_LEAVE_VEHICLE &&
+							    pPassengers[i]->CharCreatedBy != MISSION_CHAR) {
+								pPassengers[i]->bFleeAfterExitingCar = true;
+								pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+								pPassengers[i]->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time;
+// TODO(MIAMI):
+//								pPassengers[i]->Say(120);
+								time += 200;
+							}
 						}
 					}
 					break;
@@ -691,7 +1234,7 @@ CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage
 					break;
 				}
 			}
-			if (oldHealth > DAMAGE_HEALTH_TO_CATCH_FIRE && m_fHealth < DAMAGE_HEALTH_TO_CATCH_FIRE) {
+			if (oldHealth >= DAMAGE_HEALTH_TO_CATCH_FIRE && m_fHealth < DAMAGE_HEALTH_TO_CATCH_FIRE) {
 				if (IsCar()) {
 					CAutomobile* pThisCar = (CAutomobile*)this;
 					pThisCar->Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE);
@@ -725,11 +1268,13 @@ CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage
 void
 CVehicle::DoFixedMachineGuns(void)
 {
-	if(CPad::GetPad(0)->GetCarGunFired() && !bGunSwitchedOff){
-		FireFixedMachineGuns();
-	}else{
-		if(CTimer::GetTimeInMilliseconds() > m_nGunFiringTime + 1400)
-			m_nAmmoInClip = 20;
+	if(TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_FORWARD){
+		if(CPad::GetPad(0)->GetCarGunFired() && !bGunSwitchedOff){
+			FireFixedMachineGuns();
+		}else{
+			if(CTimer::GetTimeInMilliseconds() > m_nGunFiringTime + 1400)
+				m_nAmmoInClip = 20;
+		}
 	}
 }
 
@@ -777,10 +1322,44 @@ CVehicle::FireFixedMachineGuns(void)
 	}
 }
 
+void
+CVehicle::ActivateBomb(void)
+{
+	if(m_bombType == CARBOMB_TIMED){
+		m_bombType = CARBOMB_TIMEDACTIVE;
+		m_nBombTimer = 7000;
+		m_pBlowUpEntity = FindPlayerPed();
+		CGarages::TriggerMessage("GA_12", -1, 3000, -1);
+		DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TIMED_ACTIVATED, 1.0f);
+	}else if(m_bombType == CARBOMB_ONIGNITION){
+		m_bombType = CARBOMB_ONIGNITIONACTIVE;
+		CGarages::TriggerMessage("GA_12", -1, 3000, -1);
+		DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_ONIGNITION_ACTIVATED, 1.0f);
+	}
+}
+
+void
+CVehicle::ActivateBombWhenEntered(void)
+{
+	if(pDriver){
+		if(!bDriverLastFrame && m_bombType == CARBOMB_ONIGNITIONACTIVE){
+			// If someone enters the car and there is a bomb, detonate
+			m_nBombTimer = 1000;
+			m_pBlowUpEntity = m_pBombRigger;
+			if(m_pBlowUpEntity)
+				m_pBlowUpEntity->RegisterReference((CEntity**)&m_pBlowUpEntity);
+			DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TICK, 1.0f);
+		}
+		bDriverLastFrame = true;
+	}else
+		bDriverLastFrame = false;
+}
+
 void
 CVehicle::ExtinguishCarFire(void)
 {
-	m_fHealth = Max(m_fHealth, 300.0f);
+	if(GetStatus() != STATUS_WRECKED)
+		m_fHealth = Max(m_fHealth, 300.0f);
 	if(m_pCarFire)
 		m_pCarFire->Extinguish();
 	if(IsCar()){
@@ -850,6 +1429,69 @@ CVehicle::ShufflePassengersToMakeSpace(void)
 	return false;
 }
 
+void
+CVehicle::MakeNonDraggedPedsLeaveVehicle(CPed *ped1, CPed *ped2, CPlayerPed *&player, CCopPed *&cop)
+{
+	int i;
+	player = nil;
+	cop = nil;
+
+	if(ped1->IsPlayer() && ped2->m_nPedType == PEDTYPE_COP &&
+	   ((CPlayerPed*)ped1)->m_pWanted->m_nWantedLevel > 0 &&
+	   ped2->m_pedInObjective == ped1){
+		player = (CPlayerPed*)ped1;
+		cop = (CCopPed*)ped2;
+		return;
+	}
+
+	bool ped1IsDriver = ped1 == pDriver;
+
+	// Just what the hell is this weird code?
+	CPed *peds[9];
+	CPed *peds2[9];
+	int numPeds = 0;
+	int numPeds2 = 0;
+	for(i = 0; i < m_nNumMaxPassengers; i++){
+		CPed *p = pPassengers[i];
+		if(p && p != ped1 && !p->bStayInCarOnJack){
+			peds[numPeds++] = p;
+			// uhh what?
+			if(i < 1 && !ped1IsDriver)
+				continue;
+			peds2[numPeds2++] = p;
+		}
+	}
+
+	// So we're copying this array for no reason...
+	CPed *peds3[9];
+	int numPeds3 = 0;
+	for(i = 0; i < numPeds; i++){
+		if(peds[i]->IsPlayer() && ped2->m_nPedType == PEDTYPE_COP &&
+		   ((CPlayerPed*)peds[i])->m_pWanted->m_nWantedLevel > 0 &&
+		   ped2->m_pedInObjective == peds[i]){
+			player = (CPlayerPed*)peds[i];
+			cop = (CCopPed*)ped2;
+			return;
+		}
+		peds3[numPeds3++] = peds[i];
+	}
+
+	int time = 1800;
+	for(i = 0; i < numPeds3; i++){
+		peds3[i]->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + time;
+		peds3[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+		time += CGeneral::GetRandomNumberInRange(300.0f, 600.0f);
+	}
+
+	if(IsCar() && numPeds2 > 0 && CGeneral::GetRandomTrueFalse())
+		for(i = 0; i < numPeds2; i++)
+			if(peds2[i]->IsFemale() || CGeneral::GetRandomTrueFalse()){
+				peds2[i]->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 10000;
+				peds2[i]->b156_8 = true;
+				peds2[i]->bFleeAfterExitingCar = true;
+			}
+}
+
 void
 CVehicle::ProcessDelayedExplosion(void)
 {
@@ -869,8 +1511,6 @@ CVehicle::ProcessDelayedExplosion(void)
 	if (m_nBombTimer != 0)
 		return;
 
-	if(FindPlayerVehicle() != this && m_pBlowUpEntity == FindPlayerPed())
-		CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
 	BlowUpCar(m_pBlowUpEntity);
 }
 
@@ -878,12 +1518,13 @@ bool
 CVehicle::IsLawEnforcementVehicle(void)
 {
 	switch(GetModelIndex()){
-	case MI_FBICAR:
 	case MI_POLICE:
 	case MI_ENFORCER:
 	case MI_PREDATOR:
 	case MI_RHINO:
 	case MI_BARRACKS:
+	case MI_FBIRANCH:
+	case MI_VICECHEE:
 		return true;
 	default:
 		return false;
@@ -901,6 +1542,8 @@ CVehicle::UsesSiren(uint32 id)
 	case MI_POLICE:
 	case MI_ENFORCER:
 	case MI_PREDATOR:
+	case MI_FBIRANCH:
+	case MI_VICECHEE:
 		return true;
 	default:
 		return false;
@@ -989,19 +1632,27 @@ CVehicle::CanPedOpenLocks(CPed *ped)
 {
 	if(m_nDoorLock == CARLOCK_LOCKED ||
 	   m_nDoorLock == CARLOCK_LOCKED_INITIALLY ||
-	   m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE)
+	   m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE ||
+	   m_nDoorLock == CARLOCK_SKIP_SHUT_DOORS)
 		return false;
 	if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY)
 		return false;
 	return true;
 }
 
+bool
+CVehicle::CanDoorsBeDamaged(void)
+{
+	return m_nDoorLock == CARLOCK_NOT_USED ||
+		m_nDoorLock == CARLOCK_UNLOCKED ||
+		m_nDoorLock == CARLOCK_SKIP_SHUT_DOORS;
+}
+
 bool
 CVehicle::CanPedEnterCar(void)
 {
-	CVector up = GetUp();
 	// can't enter when car is on side
-	if(up.z > 0.1f || up.z < -0.1f){
+	if(IsBike() || GetUp().z > 0.1f ||  GetUp().z < -0.1f){
 		// also when car is moving too fast
 		if(m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f))
 			return false;
@@ -1013,16 +1664,14 @@ CVehicle::CanPedEnterCar(void)
 }
 
 bool
-CVehicle::CanPedExitCar(void)
+CVehicle::CanPedExitCar(bool jumpExit)
 {
 	CVector up = GetUp();
 	if(up.z > 0.1f || up.z < -0.1f){
-#ifdef VC_PED_PORTS
 		if (IsBoat())
 			return true;
-#endif
 		// can't exit when car is moving too fast
-		if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f)
+		if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f && !jumpExit)
 			return false;
 		// if car is slow enough, check turn speed
 		if(Abs(m_vecTurnSpeed.x) > 0.01f ||
@@ -1045,6 +1694,14 @@ CVehicle::CanPedExitCar(void)
 	}
 }
 
+bool
+CVehicle::CanPedJumpOffBike(void)
+{
+	if(pPassengers[0])
+		return false;
+	return m_vecMoveSpeed.MagnitudeSqr() < 0.07f ? false : true;
+}
+
 void
 CVehicle::ChangeLawEnforcerState(uint8 enable)
 {
@@ -1082,14 +1739,30 @@ CVehicle::SetUpDriver(void)
 CPed*
 CVehicle::SetupPassenger(int n)
 {
+	int i;
+
 	if(pPassengers[n])
 		return pPassengers[n];
 
-	pPassengers[n] = CPopulation::AddPedInCar(this, false);
-	pPassengers[n]->m_pMyVehicle = this;
-	pPassengers[n]->m_pMyVehicle->RegisterReference((CEntity**)&pPassengers[n]->m_pMyVehicle);
-	pPassengers[n]->bInVehicle = true;
-	pPassengers[n]->SetPedState(PED_DRIVING);
+	if((IsTaxi() || IsLimo()) && n == 0)
+		pPassengers[0] = nil;
+	else{
+		CPed *passenger = CPopulation::AddPedInCar(this, false);
+		pPassengers[n] = passenger;
+		passenger->m_pMyVehicle = this;
+		passenger->m_pMyVehicle->RegisterReference((CEntity**)&pPassengers[n]->m_pMyVehicle);
+		passenger->bInVehicle = true;
+		passenger->SetPedState(PED_DRIVING);
+
+		if(passenger->m_nPedType == PEDTYPE_CIVMALE || passenger->m_nPedType == PEDTYPE_CIVFEMALE)
+			for(i = 0; i < n; i++)
+				if(pPassengers[i] && pPassengers[n] &&
+				   pPassengers[i]->m_nPedType == PEDTYPE_CIVMALE || pPassengers[i]->m_nPedType == PEDTYPE_CIVFEMALE &&
+				   passenger->GetModelIndex() == pPassengers[i]->GetModelIndex()){
+					pPassengers[n] = nil;
+					CPopulation::RemovePed(passenger);
+				}
+	}
 	if(bIsBus)
 		pPassengers[n]->bRenderPedInCar = false;
 	++m_nNumPassengers;
@@ -1103,24 +1776,42 @@ CVehicle::SetDriver(CPed *driver)
 	pDriver->RegisterReference((CEntity**)&pDriver);
 
 	if(bFreebies && driver == FindPlayerPed()){
-		if(GetModelIndex() == MI_AMBULAN)
-			FindPlayerPed()->m_fHealth = Min(FindPlayerPed()->m_fHealth + 20.0f, CWorld::Players[0].m_nMaxHealth);
-		else if(GetModelIndex() == MI_TAXI)
-			CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25;
-		else if (GetModelIndex() == MI_POLICE) {
-			CStreaming::RequestModel(WEAPONTYPE_SHOTGUN, STREAMFLAGS_DONT_REMOVE);
-			driver->GiveWeapon(WEAPONTYPE_SHOTGUN, 5);
-		} else if (GetModelIndex() == MI_ENFORCER)
-			driver->m_fArmour = Max(driver->m_fArmour, CWorld::Players[0].m_nMaxArmour);
-		else if(GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_ZEBRA)	// TODO(MIAMI): check zebra
-			CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25;
 		bFreebies = false;
+		switch(GetModelIndex()){
+		case MI_AMBULAN:
+			FindPlayerPed()->m_fHealth = Max(FindPlayerPed()->m_fHealth, Min(FindPlayerPed()->m_fHealth + 20.0f, CWorld::Players[0].m_nMaxHealth));
+			break;
+
+		case MI_TAXI:
+		case MI_CABBIE:
+		case MI_ZEBRA:
+		case MI_KAUFMAN:
+			CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 12;
+			break;
+
+		case MI_POLICE:
+			CStreaming::RequestModel(MI_SHOTGUN, STREAMFLAGS_DONT_REMOVE);
+			bFreebies = true;
+			break;
+
+		case MI_ENFORCER:
+			driver->m_fArmour = Max(driver->m_fArmour, CWorld::Players[0].m_nMaxArmour);
+			break;
+
+		case MI_CADDY:
+			if(!(driver->IsPlayer() && ((CPlayerPed*)driver)->DoesPlayerWantNewWeapon(WEAPONTYPE_GOLFCLUB, true)))
+				CStreaming::RequestModel(MI_GOLFCLUB, STREAMFLAGS_DONT_REMOVE);
+			break;
+		}
 	}
 
-	ApplyTurnForce(0.0f, 0.0f, -0.2f*driver->m_fMass,
-		driver->GetPosition().x - GetPosition().x,
-		driver->GetPosition().y - GetPosition().y,
-		0.0f);
+	if(IsBike())
+		ApplyMoveForce(-0.2f*driver->m_fMass * GetUp());
+	else
+		ApplyTurnForce(0.0f, 0.0f, -0.2f*driver->m_fMass,
+			driver->GetPosition().x - GetPosition().x,
+			driver->GetPosition().y - GetPosition().y,
+			0.0f);
 }
 
 bool
@@ -1128,10 +1819,13 @@ CVehicle::AddPassenger(CPed *passenger)
 {
 	int i;
 
-	ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass,
-		passenger->GetPosition().x - GetPosition().x,
-		passenger->GetPosition().y - GetPosition().y,
-		0.0f);
+	if(IsBike())
+		ApplyTurnForce(-0.2f*passenger->m_fMass * GetUp(), -0.1f*GetForward());
+	else
+		ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass,
+			passenger->GetPosition().x - GetPosition().x,
+			passenger->GetPosition().y - GetPosition().y,
+			0.0f);
 
 	for(i = 0; i < m_nNumMaxPassengers; i++)
 		if(pPassengers[i] == nil){
@@ -1148,10 +1842,13 @@ CVehicle::AddPassenger(CPed *passenger, uint8 n)
 	if(bIsBus)
 		return AddPassenger(passenger);
 
-	ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass,
-		passenger->GetPosition().x - GetPosition().x,
-		passenger->GetPosition().y - GetPosition().y,
-		0.0f);
+	if(IsBike())
+		ApplyTurnForce(-0.2f*passenger->m_fMass * GetUp(), -0.1f*GetForward());
+	else
+		ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass,
+			passenger->GetPosition().x - GetPosition().x,
+			passenger->GetPosition().y - GetPosition().y,
+			0.0f);
 
 	if(n < m_nNumMaxPassengers && pPassengers[n] == nil){
 		pPassengers[n] = passenger;
@@ -1165,6 +1862,22 @@ void
 CVehicle::RemoveDriver(void)
 {
 	SetStatus(STATUS_ABANDONED);
+	if(pDriver == FindPlayerPed()){
+		if(GetModelIndex() == MI_POLICE && CStreaming::HasModelLoaded(MI_SHOTGUN)){
+			if(bFreebies){
+				if(((CPlayerPed*)pDriver)->DoesPlayerWantNewWeapon(WEAPONTYPE_SHOTGUN, true))
+					pDriver->GiveWeapon(WEAPONTYPE_SHOTGUN, 5, true);
+				else
+					pDriver->GrantAmmo(WEAPONTYPE_SHOTGUN, 5);
+				bFreebies = false;
+			}
+			CStreaming::SetModelIsDeletable(MI_SHOTGUN);
+		}else if(GetModelIndex() == MI_CADDY && CStreaming::HasModelLoaded(MI_GOLFCLUB)){
+			if(((CPlayerPed*)pDriver)->DoesPlayerWantNewWeapon(WEAPONTYPE_GOLFCLUB, true))
+				pDriver->GiveWeapon(WEAPONTYPE_GOLFCLUB, 1, true);
+			CStreaming::SetModelIsDeletable(MI_GOLFCLUB);
+		}
+	}
 	pDriver = nil;
 }
 
@@ -1190,6 +1903,57 @@ CVehicle::RemovePassenger(CPed *p)
 	}
 }
 
+bool
+CVehicle::IsDriver(CPed *ped)
+{
+	if(ped == nil)
+		return false;
+	return ped == pDriver;
+}
+
+bool
+CVehicle::IsDriver(int32 model)
+{
+	return pDriver && pDriver->GetModelIndex() == model;
+}
+
+bool
+CVehicle::IsPassenger(CPed *ped)
+{
+	int i;
+	if(ped == nil)
+		return false;
+	for(i = 0; i < 8; i++)
+		if(pPassengers[i] == ped)
+			return true;
+	return false;
+}
+
+bool
+CVehicle::IsPassenger(int32 model)
+{
+	int i;
+	for(i = 0; i < 8; i++)
+		if(pPassengers[i] && pPassengers[i]->GetModelIndex() == model)
+			return true;
+	return false;
+}
+
+void
+CVehicle::UpdatePassengerList(void)
+{
+	int i;
+	bool hasPassenger = false;
+	if(m_nNumPassengers)
+		for(i = 0; i < 8; i++)
+			if(pPassengers[i]){
+				hasPassenger = true;
+				break;
+			}
+	if(!hasPassenger)
+		m_nNumPassengers = 0;
+}
+
 void
 CVehicle::ProcessCarAlarm(void)
 {
@@ -1199,9 +1963,10 @@ CVehicle::ProcessCarAlarm(void)
 		return;
 
 	step = CTimer::GetTimeStepInMilliseconds();
-	if((uint16)m_nAlarmState < step)
+	if((uint16)m_nAlarmState < step){
 		m_nAlarmState = 0;
-	else
+		m_nCarHornTimer = 0;
+	}else
 		m_nAlarmState -= step;
 }
 
@@ -1229,6 +1994,261 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius)
 	return true;
 }
 
+RpMaterial*
+SetCompAlphaCB(RpMaterial *material, void *data)
+{
+	uint32 alpha = (uint32)(uintptr)data;
+	RwRGBA *col = (RwRGBA*)RpMaterialGetColor(material);	// get rid of const
+	col->alpha = alpha;
+	return material;
+}
+
+void
+CVehicle::SetComponentAtomicAlpha(RpAtomic *atomic, int32 alpha)
+{
+	RpGeometry *geo = RpAtomicGetGeometry(atomic);
+	RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) | rpGEOMETRYMODULATEMATERIALCOLOR);
+	RpGeometryForAllMaterials(geo, SetCompAlphaCB, (void*)alpha);
+}
+
+void
+CVehicle::UpdateClumpAlpha(void)
+{
+	int clumpAlpha = CVisibilityPlugins::GetClumpAlpha((RpClump*)m_rwObject);
+	if(bFadeOut){
+		clumpAlpha -= 8;
+		if(clumpAlpha < 0)
+			clumpAlpha = 0;
+	}else if(clumpAlpha < 255){
+		clumpAlpha += 16;
+		if(clumpAlpha > 255)
+			clumpAlpha = 255;
+	}
+	CVisibilityPlugins::SetClumpAlpha((RpClump*)m_rwObject, clumpAlpha);
+}
+
+void
+CVehicle::HeliDustGenerate(CEntity *heli, float radius, float ground, int rnd)
+{
+	int i;
+	float angle;
+	CColPoint point;
+	CEntity *entity;
+	uint8 r, g, b;
+
+	if(heli == nil)
+		return;
+
+	uint8 surface = SURFACE_TARMAC;
+	int frm = CTimer::GetFrameCounter() & 7;
+	float testLowZ = ground - 10.0f;
+	float dustSize = 0.0f;
+	float baseSize = 1.0f;
+	float offset = 1.0f;	// when heli is tilted
+	float particleZ = -101.0f;
+	int n = 0;
+
+	if(heli->GetModelIndex() == MI_RCGOBLIN || heli->GetModelIndex() == MI_RCRAIDER){
+		radius = 3.0f;
+		dustSize = 0.04f;
+		baseSize = 0.07f;
+		offset = 0.3f;
+	}
+
+	CVector heliPos = heli->GetPosition();
+
+	if(heli->IsVehicle() && ((CVehicle*)heli)->IsCar()){
+		heliPos.x -= (heliPos.z - ground)*heli->GetUp().x*offset*0.5f;
+		heliPos.y -= (heliPos.z - ground)*heli->GetUp().y*offset*0.5f;
+	}
+
+	float steamSize = 0.25f * radius * baseSize;
+	float splashSize = 0.3f * radius * baseSize;
+
+	i = 0;
+	for(i = 0; i < 32+rnd; i++){
+		angle = i * TWOPI/32.0f;
+		CVector pos(radius*Cos(angle), radius*Sin(angle), 0.0f);
+		CVector dir = CVector(pos.x, pos.y, 1.0f)*0.01f;
+		pos += heliPos;
+
+		if(i < 32 && i == 4*frm){
+			if(CWorld::ProcessVerticalLine(pos, testLowZ, point, entity, true, false, false, false, true, false, nil)){
+				n = rnd;
+				particleZ = point.point.z;
+				surface = point.surfaceB;
+			}else
+				n = 0;
+
+			float waterLevel = 0.0f;
+			if(CWaterLevel::GetWaterLevel(pos, &waterLevel, false) && waterLevel > particleZ){
+				surface = SURFACE_PUDDLE;
+				n = rnd;
+				particleZ = waterLevel;
+			}
+		}
+
+		if(n){
+			pos.z = particleZ;
+			if(surface == SURFACE_PUDDLE){
+				float red = (0.3*CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed_Obj())*255.0f/4.0f;
+				float green = (0.3*CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen_Obj())*255.0f/4.0f;
+				float blue = (0.3*CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue_Obj())*255.0f/4.0f;
+				r = clamp(red, 0.0f, 255.0f);
+				g = clamp(green, 0.0f, 255.0f);
+				b = clamp(blue, 0.0f, 255.0f);
+				RwRGBA col1 = { r, g, b, CGeneral::GetRandomNumberInRange(8, 32) };
+				RwRGBA col2 = { 255, 255, 255, 32 };
+
+				if(n&1)
+					CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, pos, dir, nil, steamSize, col2);
+				else
+					CParticle::AddParticle(PARTICLE_CAR_SPLASH, pos, dir, nil, splashSize, col1,
+						CGeneral::GetRandomNumberInRange(0.0f, 10.0f),
+						CGeneral::GetRandomNumberInRange(0.0f, 90.0f), 1);
+			}else{
+				switch(surface){
+				default:
+				case SURFACE_TARMAC:
+					r = 10;
+					g = 10;
+					b = 10;
+					break;
+				case SURFACE_GRASS:
+					r = 10;
+					g = 10;
+					b = 3;
+					break;
+				case SURFACE_DIRT:
+					r = 10;
+					g = 8;
+					b = 7;
+					break;
+				case SURFACE_DIRTTRACK:
+					r = 10;
+					g = 6;
+					b = 3;
+					break;
+				case SURFACE_SAND:
+				case SURFACE_SAND33:
+					r = 10;
+					g = 10;
+					b = 7;
+					break;
+				}
+				RwRGBA col = { r, g, b, 32 };
+				if(heliPos.z - pos.z < 20.0f)
+					CParticle::AddParticle(PARTICLE_HELI_DUST, pos, dir, nil, dustSize, col);
+			}
+
+			n--;
+		}
+	}
+}
+
+#define GLARE_MIN_DIST (13.0f)
+#define GLARE_FULL_DIST (30.0f)
+#define GLARE_MIN_ANGLE (0.99f)
+#define GLARE_FULL_ANGLE (0.995f)
+
+void
+CVehicle::DoSunGlare(void)
+{
+	if(bRenderScorched || GetPosition().z < 0.0f ||
+	   GetVehicleAppearance() != VEHICLE_APPEARANCE_CAR || CWeather::SunGlare <= 0.0f)
+		return;
+
+	CVector camDir = TheCamera.GetPosition() - GetPosition();
+	float dist = camDir.Magnitude();
+	camDir *= 2.0f/dist;
+	CVector glareVec = camDir + CTimeCycle::GetSunDirection();
+	CVector localGlareVec;
+	localGlareVec.x = DotProduct(glareVec, GetRight());
+	localGlareVec.y = DotProduct(glareVec, GetForward());
+	localGlareVec.z = 0.0;
+	localGlareVec.Normalise();
+
+	CVector2D fwd2D = GetForward();
+	fwd2D.Normalise();
+	CVector2D camDir2D = camDir;
+	camDir2D.Normalise();
+	float fwdness = Abs(DotProduct2D(fwd2D, camDir2D));
+
+	// check angle
+	float strength;
+	if(fwdness > GLARE_FULL_ANGLE)
+		strength = 1.0f;
+	else if(fwdness > GLARE_MIN_ANGLE)
+		strength = (fwdness - GLARE_MIN_ANGLE)/(GLARE_FULL_ANGLE-GLARE_MIN_ANGLE);
+	else
+		return;
+	// check distance
+	if(dist > GLARE_FULL_DIST){
+		// no max distance
+	}else if(dist > GLARE_MIN_DIST)
+		strength *= (dist - GLARE_MIN_DIST)/(GLARE_FULL_DIST - GLARE_MIN_DIST);
+	else
+		return;
+
+	float intens = 0.8f * strength * CWeather::SunGlare;
+	int r = intens * (CTimeCycle::GetSunCoreRed() + 2*255)/3.0f;
+	int g = intens * (CTimeCycle::GetSunCoreGreen() + 2*255)/3.0f;
+	int b = intens * (CTimeCycle::GetSunCoreBlue() + 2*255)/3.0f;
+
+	CColModel *colmodel = GetColModel();
+	CCollision::CalculateTrianglePlanes(colmodel);
+
+	int i;
+	for(i = 0; i < colmodel->numTriangles-2; i += 2){
+		int a1 = colmodel->triangles[i].a;
+		int b1 = colmodel->triangles[i].b;
+		int c1 = colmodel->triangles[i].c;
+		int a2 = colmodel->triangles[i+1].a;
+		int b2 = colmodel->triangles[i+1].b;
+		int c2 = colmodel->triangles[i+1].c;
+		CVector vert1 = colmodel->vertices[a1];
+		CVector vert4;
+		// Need an upward surface
+		if(vert1.z <= 0.0f)
+			continue;
+
+		// trying to find a quad here
+		int numTri2Verts = 0;
+		if(a2 != a1 && a2 != b1 && a2 != c1){
+			// a2 is not in tri1
+			numTri2Verts++;
+			vert4 = colmodel->vertices[a2];
+		}
+		if(b2 != a1 && b2 != b1 && b2 != c1){
+			// b2 is not in tri1
+			numTri2Verts++;
+			vert4 = colmodel->vertices[b2];
+		}
+		if(c2 != a1 && c2 != b1 && c2 != c1){
+			// c2 is not in tri1
+			numTri2Verts++;
+			vert4 = colmodel->vertices[c2];
+		}
+		// Need exactly one vertex from tri2 for a quad with tri1
+		if(numTri2Verts != 1)
+			continue;
+
+		CVector mid = (vert1 + colmodel->vertices[b1] + colmodel->vertices[c1] + vert4)/4.0f;
+		float dy = mid.y - vert1.y;
+		float dx = mid.x - vert1.x;
+		float dist = 1.4f * Min(Abs(dx), Abs(dy));
+		if(dist > 0.6f){
+			CVector pos = GetMatrix() * (dist * localGlareVec + mid) + camDir;
+			CCoronas::RegisterCorona((uintptr)this + 27 + i,
+				r, g, b, 255,
+				pos, 0.9f*CWeather::SunGlare, 90.0f,
+				CCoronas::TYPE_STAR, CCoronas::FLARE_NONE,
+				CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF,
+				CCoronas::STREAK_OFF, 0.0f);
+		}
+	}
+}
+
 void
 DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle)
 {
@@ -1372,20 +2392,19 @@ CVehicle::Load(uint8*& buf)
 #endif
 
 eVehicleAppearance
-//--MIAMI: TODO, implement VC version, appearance != type
-// This would work for cars, boats and bikes but not for planes and helis
 CVehicle::GetVehicleAppearance(void)
 {
-	if (IsCar())
+	uint32 flags = pHandling->Flags & 0xF0000;
+	if (flags == 0)
 		return VEHICLE_APPEARANCE_CAR;
-	if (IsBoat())
-		return VEHICLE_APPEARANCE_BOAT;
-	if (IsBike())
+	if (flags == HANDLING_IS_BIKE)
 		return VEHICLE_APPEARANCE_BIKE;
-	if (IsPlane())
-		return VEHICLE_APPEARANCE_PLANE;
-	if (IsHeli())
+	if (flags == HANDLING_IS_HELI)
 		return VEHICLE_APPEARANCE_HELI;
+	if (flags == HANDLING_IS_PLANE)
+		return VEHICLE_APPEARANCE_PLANE;
+	if (flags == HANDLING_IS_BOAT)
+		return VEHICLE_APPEARANCE_BOAT;
 	return VEHICLE_APPEARANCE_NONE;
 }
 
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 7b5a1e11..083a8a15 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -8,6 +8,8 @@
 #include "HandlingMgr.h"
 
 class CPed;
+class CPlayerPed;
+class CCopPed;
 class CFire;
 struct tHandlingData;
 
@@ -87,8 +89,8 @@ enum
 	CAR_PIECE_WING_LR,
 	CAR_PIECE_WING_RR,
 	CAR_PIECE_WHEEL_LF,
-	CAR_PIECE_WHEEL_LR,
 	CAR_PIECE_WHEEL_RF,
+	CAR_PIECE_WHEEL_LR,
 	CAR_PIECE_WHEEL_RR,
 	CAR_PIECE_WINDSCREEN,
 };
@@ -104,10 +106,12 @@ enum tWheelState
 enum eFlightModel
 {
 	FLIGHT_MODEL_DODO,
-	// not used in III
 	FLIGHT_MODEL_RCPLANE,
-	FLIGHT_MODEL_HELI,
-	FLIGHT_MODEL_SEAPLANE
+	FLIGHT_MODEL_RCHELI,
+	FLIGHT_MODEL_SEAPLANE,
+	FLIGHT_MODEL_PLANE_UNUSED,
+	FLIGHT_MODEL_PLANE,
+	FLIGHT_MODEL_HELI
 };
 
 enum eVehicleAppearance
@@ -120,10 +124,28 @@ enum eVehicleAppearance
 	VEHICLE_APPEARANCE_PLANE,
 };
 
+// TODO
+enum eBikeWheelSpecial
+{
+	BIKE_WHEEL_2 = 2,
+	BIKE_WHEEL_3,
+};
+
+enum
+{
+	ROTOR_TOP = 3,
+	ROTOR_FRONT = 4,
+	ROTOR_RIGHT = 5,
+	ROTOR_LEFT = 7,
+	ROTOR_BACK = 8,
+	ROTOR_BOTTOM = 9,
+};
+
 class CVehicle : public CPhysical
 {
 public:
 	tHandlingData *pHandling;
+	tFlyingHandlingData *pFlyingHandling;
 	CAutoPilot AutoPilot;
 	uint8 m_currentColour1;
 	uint8 m_currentColour2;
@@ -180,28 +202,28 @@ public:
 	uint8 bHasAlreadyBeenRecorded : 1; // Used for replays
 	uint8 bPartOfConvoy : 1;
 	uint8 bHeliMinimumTilt : 1; // This heli should have almost no tilt really
-	//uint8 bAudioChangingGear : 1; // sounds like vehicle is changing gear
+	uint8 bAudioChangingGear : 1; // sounds like vehicle is changing gear
 
 	uint8 bIsDrowning : 1; // is vehicle occupants taking damage in water (i.e. vehicle is dead in water)
 	uint8 bTyresDontBurst : 1; // If this is set the tyres are invincible
 	uint8 bCreatedAsPoliceVehicle : 1;// True if this guy was created as a police vehicle (enforcer, policecar, miamivice car etc)
 	uint8 bRestingOnPhysical : 1; // Dont go static cause car is sitting on a physical object that might get removed
 	uint8 bParking : 1;
-	//uint8 bCanPark : 1;
+	uint8 bCanPark : 1;
 
 	uint8 m_bombType : 3;
+	uint8 bDriverLastFrame : 1;
 
 	int8 m_numPedsUseItAsCover;
 	uint8 m_nAmmoInClip;    // Used to make the guns on boat do a reload (20 by default)
 	int8 m_nPacManPickupsCarried;
 	uint8 m_nRoadblockType;
-	int16 m_nRoadblockNode;
 	float m_fHealth;           // 1000.0f = full health. 250.0f = fire. 0 -> explode
 	uint8 m_nCurrentGear;
 	float m_fChangeGearTime;
 	CEntity* m_pBombRigger;
-	uint32 m_nGunFiringTime;    // last time when gun on vehicle was fired (used on boats)
 	uint32 m_nSetPieceExtendedRangeTime;
+	uint32 m_nGunFiringTime;    // last time when gun on vehicle was fired (used on boats)
 	uint32 m_nTimeOfDeath;
 	uint16 m_nTimeBlocked;
 	int16 m_nBombTimer;        // goes down with each frame
@@ -214,7 +236,7 @@ public:
 	int8 m_nRadioStation;
 	uint8 m_bRainAudioCounter;
 	uint8 m_bRainSamplesCounter;
-	uint8 m_nCarHornTimer;
+	uint32 m_nCarHornTimer;
 	uint8 m_nCarHornPattern;
 	bool m_bSirenOrAlarm;
 	uint8 m_nCarHornDelay;
@@ -247,11 +269,15 @@ public:
 	virtual bool IsDoorFullyOpen(eDoors door) { return false; }
 	virtual bool IsDoorClosed(eDoors door) { return false; }
 	virtual bool IsDoorMissing(eDoors door) { return false; }
+	virtual bool IsDoorReady(uint32 door) { return false; }
+	virtual bool IsDoorMissing(uint32 door) { return false; }
+	virtual bool IsOpenTopCar(void) { return false; }
 	virtual void RemoveRefsToVehicle(CEntity *ent) {}
 	virtual void BlowUpCar(CEntity *ent) {}
 	virtual bool SetUpWheelColModel(CColModel *colModel) { return false; }
-	virtual void BurstTyre(uint8 tyre) {}
+	virtual void BurstTyre(uint8 tyre, bool applyForces) {}
 	virtual bool IsRoomForPedToLeaveCar(uint32 component, CVector *forcedDoorPos) { return false;}
+	virtual bool IsClearToDriveAway(void);
 	virtual float GetHeightAboveRoad(void);
 	virtual void PlayCarHorn(void) {}
 #ifdef COMPATIBLE_SAVES
@@ -268,11 +294,17 @@ public:
 	bool IsBike(void) { return m_vehType == VEHICLE_TYPE_BIKE; }
 
 	void FlyingControl(eFlightModel flightModel);
+	bool DoBladeCollision(CVector pos, CMatrix &matrix, int16 rotorType, float radius, float damageMult);
+	bool BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &matrix, int16 rotorType, float damageMult);
+
 	void ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
 		int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus);
+	void ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
+		int32 wheelsOnGround, float thrust, float brake, float adhesion, float unk, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, eBikeWheelSpecial special, uint16 wheelStatus);
 	void ExtinguishCarFire(void);
 	void ProcessDelayedExplosion(void);
 	float ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius);
+	int FindTyreNearestPoint(float x, float y);
 	bool IsLawEnforcementVehicle(void);
 	void ChangeLawEnforcerState(uint8 enable);
 	bool UsesSiren(uint32 id);
@@ -282,8 +314,10 @@ public:
 	bool IsOnItsSide(void);
 	bool CanBeDeleted(void);
 	bool CanPedOpenLocks(CPed *ped);
+	bool CanDoorsBeDamaged(void);
 	bool CanPedEnterCar(void);
-	bool CanPedExitCar(void);
+	bool CanPedExitCar(bool jumpExit);
+	bool CanPedJumpOffBike(void);
 	// do these two actually return something?
 	CPed *SetUpDriver(void);
 	CPed *SetupPassenger(int n);
@@ -292,17 +326,31 @@ public:
 	bool AddPassenger(CPed *passenger, uint8 n);
 	void RemovePassenger(CPed *passenger);
 	void RemoveDriver(void);
+	bool IsDriver(CPed *ped);
+	bool IsDriver(int32 model);
+	bool IsPassenger(CPed *ped);
+	bool IsPassenger(int32 model);
+	void UpdatePassengerList(void);
 	void ProcessCarAlarm(void);
 	bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
 	bool ShufflePassengersToMakeSpace(void);
-	void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage);
+	void MakeNonDraggedPedsLeaveVehicle(CPed *ped1, CPed *ped2, CPlayerPed *&player, CCopPed *&cop);
+	void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage, CVector pos = CVector(0.0f, 0.0f, 0.0f));
 	void DoFixedMachineGuns(void);
 	void FireFixedMachineGuns(void);
+	void ActivateBomb(void);
+	void ActivateBombWhenEntered(void);
 
+	void SetComponentAtomicAlpha(RpAtomic *atomic, int32 alpha);
+	void UpdateClumpAlpha(void);
+
+	static void HeliDustGenerate(CEntity *heli, float radius, float ground, int rnd);
+	void DoSunGlare(void);
 
 	bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; }
 	CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
 	bool IsTaxi(void) { return GetModelIndex() == MI_TAXI || GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_ZEBRA || GetModelIndex() == MI_KAUFMAN; }
+	bool IsLimo(void) { return GetModelIndex() == MI_STRETCH || GetModelIndex() == MI_LOVEFIST; }
 	bool IsRealHeli(void) { return !!(pHandling->Flags & HANDLING_IS_HELI); }
 
 	static bool bWheelsOnlyCheat;
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index ebdeb38b..a6217d70 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -1271,7 +1271,7 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim,
 				}
 				case ENTITY_TYPE_VEHICLE:
 				{
-					((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage);
+					((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, point->point);
 
 					for ( int32 i = 0; i < 16; i++ )
 						CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f);
@@ -1648,7 +1648,7 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource)
 					case ENTITY_TYPE_VEHICLE:
 					{
 						if (point.pieceB >= SURFACE_STREET_LIGHT && point.pieceB <= SURFACE_METAL_FENCE) {
-							((CVehicle*)victim)->BurstTyre(point.pieceB); // TODO(Miami): New parameter: ,true);
+							((CVehicle*)victim)->BurstTyre(point.pieceB, true);
 
 							for (int32 i = 0; i < 4; i++)
 								CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, point.point, point.normal * 0.05f);