diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp
index 470c3d24..c98c2137 100644
--- a/src/control/CarAI.cpp
+++ b/src/control/CarAI.cpp
@@ -11,6 +11,7 @@ WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); }
 WRAPPER eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { EAXJMP(0x415E30); }
 WRAPPER int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle*) { EAXJMP(0x415EB0); }
 WRAPPER void CCarAI::AddPoliceOccupants(CVehicle*) { EAXJMP(0x415C60); }
+WRAPPER void CCarAI::TellOccupantsToLeaveCar(CVehicle*) { EAXJMP(0x415D20); }
 
 void CCarAI::CarHasReasonToStop(CVehicle* pVehicle)
 {
diff --git a/src/control/CarAI.h b/src/control/CarAI.h
index 0b0a939b..b04db021 100644
--- a/src/control/CarAI.h
+++ b/src/control/CarAI.h
@@ -13,4 +13,5 @@ public:
 	static eCarMission FindPoliceCarMissionForWantedLevel();
 	static void AddPoliceOccupants(CVehicle*);
 	static void CarHasReasonToStop(CVehicle*);
+	static void TellOccupantsToLeaveCar(CVehicle*);
 };
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 118fa5c9..94f414a8 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -52,6 +52,23 @@
 
 #define ATTEMPTS_TO_FIND_NEXT_NODE 15
 
+#define TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING 2500
+#define DISTANCE_TO_SWITCH_FROM_BLOCK_TO_STOP 5.0f
+#define DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK 10.0f
+#define MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING 0.13f
+#define DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN 40.0f
+#define MAX_ANGLE_TO_STEER_AT_HIGH_SPEED 0.2f
+#define MIN_SPEED_TO_START_LIMITING_STEER 0.45f
+#define DISTANCE_TO_NEXT_NODE_TO_SELECT_NEW 5.0f
+#define DISTANCE_TO_FACING_NEXT_NODE_TO_SELECT_NEW 8.0f
+#define DEFAULT_MAX_STEER_ANGLE 0.5f
+#define MIN_LOWERING_SPEED_COEFFICIENT 0.4f
+#define MAX_ANGLE_FOR_SPEED_LIMITING 1.2f
+#define MIN_ANGLE_FOR_SPEED_LIMITING 0.4f
+#define MIN_ANGLE_FOR_SPEED_LIMITING_BETWEEN_NODES 0.1f
+#define MIN_ANGLE_TO_APPLY_HANDBRAKE 0.7f
+#define MIN_SPEED_TO_APPLY_HANDBRAKE 0.3f
+
 int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38;
 int &CCarCtrl::NumAmbulancesOnDuty = *(int*)0x885BB0;
 int &CCarCtrl::NumFiretrucksOnDuty = *(int*)0x9411F0;
@@ -66,16 +83,15 @@ int32 &CCarCtrl::MaxNumberOfCarsInUse = *(int32*)0x5EC8B8;
 uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0;
 uint32 &CCarCtrl::LastTimeFireTruckCreated = *(uint32*)0x941450;
 uint32 &CCarCtrl::LastTimeAmbulanceCreated = *(uint32*)0x880F5C;
-int32 (&CCarCtrl::TotalNumOfCarsOfRating)[7] = *(int32(*)[7])*(uintptr*)0x8F1A60;
-int32 (&CCarCtrl::NextCarOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[7])*(uintptr*)0x9412AC;
-int32 (&CCarCtrl::CarArrays)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY] = *(int32(*)[7][MAX_CAR_MODELS_IN_ARRAY])*(uintptr*)0x6EB860;
+int32 (&CCarCtrl::TotalNumOfCarsOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x8F1A60;
+int32 (&CCarCtrl::NextCarOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x9412AC;
+int32 (&CCarCtrl::CarArrays)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY] = *(int32(*)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY])*(uintptr*)0x6EB860;
 CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP] = *(CVehicle*(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x70D830;
 
 WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
 WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); }
 WRAPPER bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool) { EAXJMP(0x41FA00); }
 WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); }
-WRAPPER void CCarCtrl::SteerAICarWithPhysics(CVehicle*) { EAXJMP(0x41DA60); }
 WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); }
 WRAPPER void CCarCtrl::GenerateEmergencyServicesCar(void) { EAXJMP(0x41FC50); }
 
@@ -393,12 +409,12 @@ CCarCtrl::GenerateOneRandomCar()
 	CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo];
 	CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo];
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurrentLink->posX + GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardY,
-		pCurrentLink->posY - GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardX,
+		pCurrentLink->posX + ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurrentLink->posY - ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY,
-		pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX,
+		pNextLink->posX + ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->posY - ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
 	float directionCurrentLinkX = pCurrentLink->dirX * pCar->AutoPilot.m_nCurrentDirection;
 	float directionCurrentLinkY = pCurrentLink->dirY * pCar->AutoPilot.m_nCurrentDirection;
@@ -771,12 +787,12 @@ CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
 	float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
 	float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurrentLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardY,
-		pCurrentLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardX,
+		pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY,
-		pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX,
+		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
 	CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f);
 	CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f);
@@ -1586,12 +1602,12 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
 	if (pVehicle->AutoPilot.m_bStayInFastLane)
 		pVehicle->AutoPilot.m_nNextLane = 0;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink), /* ...what about Y? */
-		pCurLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardX,
+		pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), /* ...what about Y? */
+		pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink),
-		pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX,
+		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH),
+		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
 	float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
 	float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
@@ -1766,12 +1782,12 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t
 	if (pVehicle->AutoPilot.m_bStayInFastLane)
 		pVehicle->AutoPilot.m_nNextLane = 0;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardY,
-		pCurLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardX,
+		pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY,
-		pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX,
+		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
 	float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
 	float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
@@ -1846,12 +1862,12 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
 	if (pVehicle->AutoPilot.m_bStayInFastLane)
 		pVehicle->AutoPilot.m_nNextLane = 0;
 	CVector positionOnCurrentLinkIncludingLane(
-		pCurLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardY,
-		pCurLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardX,
+		pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
+		pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
 		0.0f);
 	CVector positionOnNextLinkIncludingLane(
-		pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY,
-		pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX,
+		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
 		0.0f);
 	float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
 	float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
@@ -1956,7 +1972,7 @@ void CCarCtrl::DragCarToPoint(CVehicle* pVehicle, CVector* pPoint)
 		actualBehindZ = point.point.z;
 		pVehicle->m_pCurGroundEntity = pRoadObject;
 		if (ThisRoadObjectCouldMove(pRoadObject->GetModelIndex()))
-			pVehicle->m_aCollPolys[0].valid = false;
+			pVehicle->m_aCollPolys[1].valid = false;
 	}else{
 		actualBehindZ = pVehicle->m_fMapObjectHeightBehind;
 	}
@@ -1970,12 +1986,477 @@ void CCarCtrl::DragCarToPoint(CVehicle* pVehicle, CVector* pPoint)
 	pVehicle->GetPosition() = (CVector(midPos.x, midPos.y, actualBehindZ)
 		+ CVector(posTarget.x, posTarget.y, actualAheadZ)) / 2;
 	pVehicle->GetPosition().z += pVehicle->GetHeightAboveRoad();
-	debug("right: %f %f %f\n", pVehicle->GetRight().x, pVehicle->GetRight().y, pVehicle->GetRight().z);
-	debug("forward: %f %f %f\n", pVehicle->GetForward().x, pVehicle->GetForward().y, pVehicle->GetForward().z);
-	debug("up: %f %f %f\n", pVehicle->GetUp().x, pVehicle->GetUp().y, pVehicle->GetUp().z);
-	debug("pos: %f %f %f\n", pVehicle->GetPosition().x, pVehicle->GetPosition().y, pVehicle->GetPosition().z);
 }
 
+float CCarCtrl::FindSpeedMultiplier(float angleChange, float minAngle, float maxAngle, float coef)
+{
+	float actual = ((float(*)(float, float, float, float))(0x41D980))(angleChange, minAngle, maxAngle, coef);
+	float angle = Abs(LimitRadianAngle(angleChange));
+	float n = angle - minAngle;
+	n = max(0.0f, n);
+	float d = maxAngle - minAngle;
+	float mult = 1.0f - n / d * (1.0f - coef);
+	if (n > d)
+		return coef == actual ? coef : ASSERT(0), coef;
+	if (ABS(mult - actual) > 0.01f)
+		ASSERT(0);
+	return mult;
+}
+
+void CCarCtrl::SteerAICarWithPhysics(CVehicle* pVehicle)
+{
+	float swerve;
+	float accel;
+	float brake;
+	bool handbrake;
+	switch (pVehicle->AutoPilot.m_nTempAction){
+	case TEMPACT_WAIT:
+		swerve = 0.0f;
+		accel = 0.0f;
+		brake = 0.2f;
+		handbrake = false;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction){
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+			pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds();
+			pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds();
+		}
+		break;
+	case TEMPACT_REVERSE:
+		SteerAICarWithPhysics_OnlyMission(pVehicle, &swerve, &accel, &brake, &handbrake);
+		handbrake = false;
+		swerve = -swerve;
+		if (DotProduct(pVehicle->GetMoveSpeed(), pVehicle->GetForward()) > 0.04f){
+			accel = 0.0f;
+			brake = 0.5f;
+		}else{
+			accel = -0.5f;
+			brake = 0.0f;
+		}
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	case TEMPACT_HANDBRAKETURNLEFT:
+		swerve = -1.0f; // It seems like this should be swerve = 1.0f (fixed in VC)
+		accel = 0.0f;
+		brake = 0.0f;
+		handbrake = true;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	case TEMPACT_HANDBRAKETURNRIGHT:
+		swerve = 1.0f; // It seems like this should be swerve = -1.0f (fixed in VC)
+		accel = 0.0f;
+		brake = 0.0f;
+		handbrake = true;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	case TEMPACT_HANDBRAKESTRAIGHT:
+		swerve = 0.0f;
+		accel = 0.0f;
+		brake = 0.0f;
+		handbrake = true;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	case TEMPACT_TURNLEFT:
+		swerve = 1.0f;
+		accel = 1.0f;
+		brake = 0.0f;
+		handbrake = false;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	case TEMPACT_TURNRIGHT:
+		swerve = -1.0f;
+		accel = 1.0f;
+		brake = 0.0f;
+		handbrake = false;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	case TEMPACT_GOFORWARD:
+		swerve = 0.0f;
+		accel = 0.5f;
+		brake = 0.0f;
+		handbrake = false;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	case TEMPACT_SWERVELEFT:
+	case TEMPACT_SWERVERIGHT:
+		swerve = (pVehicle->AutoPilot.m_nTempAction == TEMPACT_SWERVERIGHT) ? 0.15f : -0.15f;
+		accel = 0.0f;
+		brake = 0.001f;
+		handbrake = false;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction - 1000)
+			swerve = -swerve;
+		if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
+			pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+		break;
+	default:
+		SteerAICarWithPhysics_OnlyMission(pVehicle, &swerve, &accel, &brake, &handbrake);
+		break;
+	}
+	pVehicle->m_fSteerAngle = swerve;
+	pVehicle->bIsHandbrakeOn = handbrake;
+	pVehicle->m_fGasPedal = accel;
+	pVehicle->m_fBrakePedal = brake;
+}
+
+void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
+{
+	switch (pVehicle->AutoPilot.m_nCarMission) {
+	case MISSION_NONE:
+		*pSwerve = 0.0f;
+		*pAccel = 0.0f;
+		*pBrake = 0.5f;
+		*pHandbrake = true;
+		return;
+	case MISSION_CRUISE:
+	case MISSION_RAMPLAYER_FARAWAY:
+	case MISSION_BLOCKPLAYER_FARAWAY:
+	case MISSION_GOTOCOORDS:
+	case MISSION_GOTOCOORDS_ACCURATE:
+	case MISSION_RAMCAR_FARAWAY:
+	case MISSION_BLOCKCAR_FARAWAY:
+	{
+		SteerAICarWithPhysicsFollowPath(pVehicle, pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	}
+	case MISSION_RAMPLAYER_CLOSE:
+	{
+		CVector2D targetPos = FindPlayerCoors();
+		if (FindPlayerVehicle()){
+			if (pVehicle->m_randomSeed & 1 && DotProduct(FindPlayerVehicle()->GetForward(), pVehicle->GetForward()) > 0.5f){
+				float targetWidth = FindPlayerVehicle()->GetColModel()->boundingBox.max.x;
+				float ownWidth = pVehicle->GetColModel()->boundingBox.max.x;
+				if (pVehicle->m_randomSeed & 2){
+					targetPos += (targetWidth + ownWidth - 0.2f) * FindPlayerVehicle()->GetRight();
+				}else{
+					targetPos -= (targetWidth + ownWidth - 0.2f) * FindPlayerVehicle()->GetRight();
+				}
+				float targetSpeed = FindPlayerVehicle()->GetMoveSpeed().Magnitude();
+				float distanceToTarget = ((CVector2D)pVehicle->GetPosition() - targetPos).Magnitude();
+				if (12.0f * targetSpeed + 2.0f > distanceToTarget && pVehicle->AutoPilot.m_nTempAction == TEMPACT_NONE){
+					pVehicle->AutoPilot.m_nTempAction = (pVehicle->m_randomSeed & 2) ? TEMPACT_TURNLEFT : TEMPACT_TURNRIGHT;
+					pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 250;
+				}
+			}else{
+				targetPos += FindPlayerVehicle()->GetRight() / 160 * ((pVehicle->m_randomSeed & 0xFF) - 128);
+			}
+		}
+		SteerAICarWithPhysicsHeadingForTarget(pVehicle, FindPlayerVehicle(), targetPos.x, targetPos.y, pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	}
+	case MISSION_BLOCKPLAYER_CLOSE:
+		SteerAICarWithPhysicsTryingToBlockTarget(pVehicle, FindPlayerCoors().x, FindPlayerCoors().y,
+			FindPlayerSpeed().x, FindPlayerSpeed().y, pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	case MISSION_BLOCKPLAYER_HANDBRAKESTOP:
+		SteerAICarWithPhysicsTryingToBlockTarget_Stop(pVehicle, FindPlayerCoors().x, FindPlayerCoors().y,
+			FindPlayerSpeed().x, FindPlayerSpeed().y, pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	case MISSION_GOTOCOORDS_STRAIGHT:
+	case MISSION_GOTO_COORDS_STRAIGHT_ACCURATE:
+		SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil,
+			pVehicle->AutoPilot.m_vecDestinationCoors.x, pVehicle->AutoPilot.m_vecDestinationCoors.y,
+			pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	case MISSION_EMERGENCYVEHICLE_STOP:
+	case MISSION_STOP_FOREVER:
+		*pSwerve = 0.0f;
+		*pAccel = 0.0f;
+		*pHandbrake = true;
+		*pBrake = 0.5f;
+		return;
+	case MISSION_RAMCAR_CLOSE:
+		SteerAICarWithPhysicsHeadingForTarget(pVehicle, pVehicle->AutoPilot.m_pTargetCar,
+			pVehicle->AutoPilot.m_pTargetCar->GetPosition().x, pVehicle->AutoPilot.m_pTargetCar->GetPosition().y,
+			pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	case MISSION_BLOCKCAR_CLOSE:
+		SteerAICarWithPhysicsTryingToBlockTarget(pVehicle,
+			pVehicle->AutoPilot.m_pTargetCar->GetPosition().x,
+			pVehicle->AutoPilot.m_pTargetCar->GetPosition().y,
+			pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().x,
+			pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().y,
+			pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	case MISSION_BLOCKCAR_HANDBRAKESTOP:
+		SteerAICarWithPhysicsTryingToBlockTarget_Stop(pVehicle,
+			pVehicle->AutoPilot.m_pTargetCar->GetPosition().x,
+			pVehicle->AutoPilot.m_pTargetCar->GetPosition().y,
+			pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().x,
+			pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().y,
+			pSwerve, pAccel, pBrake, pHandbrake);
+		return;
+	default:
+		return;
+	}
+}
+
+void CCarCtrl::SteerAIBoatWithPhysics(CBoat* pBoat)
+{
+	if (pBoat->AutoPilot.m_nCarMission == MISSION_GOTOCOORDS_ASTHECROWSWIMS){
+		SteerAIBoatWithPhysicsHeadingForTarget(pBoat,
+			pBoat->AutoPilot.m_vecDestinationCoors.x, pBoat->AutoPilot.m_vecDestinationCoors.y,
+			&pBoat->m_fSteeringLeftRight, &pBoat->m_fAccelerate, &pBoat->m_fBrake);
+	}else if (pBoat->AutoPilot.m_nCarMission == MISSION_NONE){
+		pBoat->m_fSteeringLeftRight = 0.0f;
+		pBoat->m_fAccelerate = 0.0f;
+		pBoat->m_fBrake = 0.0f;
+	}
+	pBoat->m_fSteerAngle = pBoat->m_fSteeringLeftRight;
+	pBoat->m_fGasPedal = pBoat->m_fAccelerate;
+	pBoat->m_fBrakePedal = pBoat->m_fBrake;
+	pBoat->bIsHandbrakeOn = false;
+}
+
+float CCarCtrl::FindMaxSteerAngle(CVehicle* pVehicle)
+{
+	return pVehicle->GetModelIndex() == MI_ENFORCER ? 0.7f : DEFAULT_MAX_STEER_ANGLE;
+}
+
+void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
+{
+	CVector2D forward = pVehicle->GetForward();
+	forward.Normalise();
+	CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
+	CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
+	CVector2D currentPathLinkForward(pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection,
+		pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection);
+	float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
+	float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+	CVector2D positionOnCurrentLinkIncludingLane(
+		pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
+		pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
+	CVector2D positionOnNextLinkIncludingLane(
+		pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
+		pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX);
+	CVector2D distanceToNextNode = (CVector2D)pVehicle->GetPosition() - positionOnCurrentLinkIncludingLane;
+	float scalarDistanceToNextNode = distanceToNextNode.Magnitude();
+	CVector2D distanceBetweenNodes = positionOnNextLinkIncludingLane - positionOnCurrentLinkIncludingLane;
+	float dp = DotProduct2D(distanceBetweenNodes, distanceToNextNode);
+	if (scalarDistanceToNextNode < DISTANCE_TO_NEXT_NODE_TO_SELECT_NEW ||
+	  dp > 0.0f && scalarDistanceToNextNode < DISTANCE_TO_FACING_NEXT_NODE_TO_SELECT_NEW ||
+	  dp / (scalarDistanceToNextNode * distanceBetweenNodes.Magnitude()) > 0.7f ||
+	  pVehicle->AutoPilot.m_nNextPathNodeInfo == pVehicle->AutoPilot.m_nCurrentPathNodeInfo){
+		if (PickNextNodeAccordingStrategy(pVehicle)) {
+			switch (pVehicle->AutoPilot.m_nCarMission){
+			case MISSION_GOTOCOORDS:
+				pVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT;
+				*pSwerve = 0.0f;
+				*pAccel = 0.0f;
+				*pBrake = 0.0f;
+				*pHandbrake = false;
+				return;
+			case MISSION_GOTOCOORDS_ACCURATE:
+				pVehicle->AutoPilot.m_nCarMission = MISSION_GOTO_COORDS_STRAIGHT_ACCURATE;
+				*pSwerve = 0.0f;
+				*pAccel = 0.0f;
+				*pBrake = 0.0f;
+				*pHandbrake = false;
+				return;
+			}
+		}
+		pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
+		scalarDistanceToNextNode = CVector2D(
+			pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y - pVehicle->GetPosition().x,
+			pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x - pVehicle->GetPosition().y).Magnitude();		
+		pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
+		currentPathLinkForward.x = pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
+		currentPathLinkForward.y = pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
+		nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
+		nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+	}
+	positionOnCurrentLinkIncludingLane.x = pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y;
+	positionOnCurrentLinkIncludingLane.y = pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x;
+	CVector2D projectedPosition = positionOnCurrentLinkIncludingLane - currentPathLinkForward * scalarDistanceToNextNode * 0.4f;
+	if (scalarDistanceToNextNode > DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN){
+		projectedPosition.x = positionOnCurrentLinkIncludingLane.x;
+		projectedPosition.y = positionOnCurrentLinkIncludingLane.y;
+	}
+	CVector2D distanceToProjectedPosition = projectedPosition - pVehicle->GetPosition();
+	float angleCurrentLink = CGeneral::GetATanOfXY(distanceToProjectedPosition.x, distanceToProjectedPosition.y);
+	float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y);
+	if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_AVOID_CARS)
+		angleCurrentLink = FindAngleToWeaveThroughTraffic(pVehicle, nil, angleCurrentLink, angleForward);
+	float steerAngle = LimitRadianAngle(angleCurrentLink - angleForward);
+	float maxAngle = FindMaxSteerAngle(pVehicle);
+	steerAngle = min(maxAngle, max(-maxAngle, steerAngle));
+	if (pVehicle->GetMoveSpeed().Magnitude() > MIN_SPEED_TO_START_LIMITING_STEER)
+		steerAngle = min(MAX_ANGLE_TO_STEER_AT_HIGH_SPEED, max(-MAX_ANGLE_TO_STEER_AT_HIGH_SPEED, steerAngle));
+	float currentForwardSpeed = DotProduct(pVehicle->GetMoveSpeed(), pVehicle->GetForward()) * GAME_SPEED_TO_CARAI_SPEED;
+	float speedStyleMultiplier;
+	switch (pVehicle->AutoPilot.m_nDrivingStyle) {
+	case DRIVINGSTYLE_STOP_FOR_CARS:
+	case DRIVINGSTYLE_SLOW_DOWN_FOR_CARS:
+		speedStyleMultiplier = FindMaximumSpeedForThisCarInTraffic(pVehicle) / pVehicle->AutoPilot.m_nCruiseSpeed;
+		break;
+	default:
+		speedStyleMultiplier = 1.0f;
+		break;
+	}
+	switch (pVehicle->AutoPilot.m_nDrivingStyle) {
+	case DRIVINGSTYLE_STOP_FOR_CARS:
+	case DRIVINGSTYLE_SLOW_DOWN_FOR_CARS:
+		if (CTrafficLights::ShouldCarStopForLight(pVehicle, false)){
+			CCarAI::CarHasReasonToStop(pVehicle);
+			speedStyleMultiplier = 0.0f;
+		}
+		break;
+	default:
+		break;
+	}
+	if (CTrafficLights::ShouldCarStopForBridge(pVehicle)){
+		CCarAI::CarHasReasonToStop(pVehicle);
+		speedStyleMultiplier = 0.0f;
+	}
+	CVector2D trajectory(pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
+		pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
+	trajectory -= pVehicle->GetPosition();
+	float speedAngleMultiplier = FindSpeedMultiplier(
+		CGeneral::GetATanOfXY(trajectory.x, trajectory.y) - angleForward,
+		MIN_ANGLE_FOR_SPEED_LIMITING, MAX_ANGLE_FOR_SPEED_LIMITING, MIN_LOWERING_SPEED_COEFFICIENT);
+	float tmpWideMultiplier = FindSpeedMultiplier(
+		CGeneral::GetATanOfXY(currentPathLinkForward.x, currentPathLinkForward.y) -
+		CGeneral::GetATanOfXY(nextPathLinkForwardX, nextPathLinkForwardY),
+		MIN_ANGLE_FOR_SPEED_LIMITING_BETWEEN_NODES, MAX_ANGLE_FOR_SPEED_LIMITING, MIN_LOWERING_SPEED_COEFFICIENT);
+	float speedNodesMultiplier;
+	if (scalarDistanceToNextNode > DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN || pVehicle->AutoPilot.m_nCruiseSpeed < 12)
+		speedNodesMultiplier = 1.0f;
+	else
+		speedNodesMultiplier = 1.0f -
+			(1.0f - scalarDistanceToNextNode / DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN) *
+			(1.0f - tmpWideMultiplier);
+	float speedMultiplier = min(speedStyleMultiplier, min(speedAngleMultiplier, speedNodesMultiplier));
+	float speed = pVehicle->AutoPilot.m_nCruiseSpeed * speedMultiplier;
+	float speedDifference = speed - currentForwardSpeed;
+	if (speed < 0.05f && speedDifference < 0.03f){
+		*pBrake = 1.0f;
+		*pAccel = 0.0f;
+	}else if (speedDifference <= 0.0f){
+		*pBrake = min(0.5f, -speedDifference * 0.05f);
+		*pAccel = 0.0f;
+	}else if (currentForwardSpeed < 2.0f){
+		*pBrake = 0.0f;
+		*pAccel = min(1.0f, speedDifference * 0.25f);
+	}else{
+		*pBrake = 0.0f;
+		*pAccel = min(1.0f, speedDifference * 0.125f);
+	}
+	*pSwerve = steerAngle;
+	*pHandbrake = false;
+}
+
+void CCarCtrl::SteerAICarWithPhysicsHeadingForTarget(CVehicle* pVehicle, CPhysical* pTarget, float targetX, float targetY, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
+{
+	*pHandbrake = false;
+	CVector2D forward = pVehicle->GetForward();
+	forward.Normalise();
+	float angleToTarget = CGeneral::GetATanOfXY(targetX - pVehicle->GetPosition().x, targetY - pVehicle->GetPosition().y);
+	float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y);
+	if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_AVOID_CARS)
+		angleToTarget = FindAngleToWeaveThroughTraffic(pVehicle, pTarget, angleToTarget, angleForward);
+	float steerAngle = LimitRadianAngle(angleToTarget - angleForward);
+	if (pVehicle->GetMoveSpeed().Magnitude() > MIN_SPEED_TO_APPLY_HANDBRAKE)
+		if (ABS(steerAngle) > MIN_ANGLE_TO_APPLY_HANDBRAKE)
+			*pHandbrake = true;
+	float maxAngle = FindMaxSteerAngle(pVehicle);
+	steerAngle = min(maxAngle, max(-maxAngle, steerAngle));
+	float speedMultiplier = FindSpeedMultiplier(angleToTarget - angleForward,
+		MIN_ANGLE_FOR_SPEED_LIMITING, MAX_ANGLE_FOR_SPEED_LIMITING, MIN_LOWERING_SPEED_COEFFICIENT);
+	float speedTarget = pVehicle->AutoPilot.m_nCruiseSpeed * speedMultiplier;
+	float currentSpeed = pVehicle->GetMoveSpeed().Magnitude() * GAME_SPEED_TO_CARAI_SPEED;
+	float speedDiff = speedTarget - currentSpeed;
+	if (speedDiff <= 0.0f){
+		*pAccel = 0.0f;
+		*pBrake = min(0.5f, -speedDiff * 0.05f);
+	}else if (currentSpeed < 25.0f){
+		*pAccel = min(1.0f, speedDiff * 0.1f);
+		*pBrake = 0.0f;
+	}else{
+		*pAccel = 1.0f;
+		*pBrake = 0.0f;
+	}
+	*pSwerve = steerAngle;
+}
+
+void CCarCtrl::SteerAICarWithPhysicsTryingToBlockTarget(CVehicle* pVehicle, float targetX, float targetY, float targetSpeedX, float targetSpeedY, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
+{
+	CVector2D targetPos(targetX, targetY);
+	CVector2D offset(targetSpeedX, targetSpeedY);
+	float trajectoryLen = offset.Magnitude();
+	if (trajectoryLen > MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING)
+		offset *= MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING / trajectoryLen;
+	targetPos += offset * GAME_SPEED_TO_CARAI_SPEED;
+	pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
+	SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil, targetPos.x, targetPos.y, pSwerve, pAccel, pBrake, pHandbrake);
+	if ((targetPos - pVehicle->GetPosition()).MagnitudeSqr() < SQR(DISTANCE_TO_SWITCH_FROM_BLOCK_TO_STOP))
+		pVehicle->AutoPilot.m_nCarMission = (pVehicle->AutoPilot.m_nCarMission == MISSION_BLOCKCAR_CLOSE) ?
+			MISSION_BLOCKCAR_HANDBRAKESTOP : MISSION_BLOCKPLAYER_HANDBRAKESTOP;
+}
+void CCarCtrl::SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle* pVehicle, float targetX, float targetY, float targetSpeedX, float targetSpeedY, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
+{
+	*pSwerve = 0.0f;
+	*pAccel = 0.0f;
+	*pBrake = 1.0f;
+	*pHandbrake = true;
+	float distanceToTargetSqr = (CVector2D(targetX, targetY) - pVehicle->GetPosition()).MagnitudeSqr();
+	if (distanceToTargetSqr > SQR(DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK)){
+		pVehicle->AutoPilot.m_nCarMission = (pVehicle->AutoPilot.m_nCarMission == MISSION_BLOCKCAR_HANDBRAKESTOP) ?
+			MISSION_BLOCKCAR_CLOSE : MISSION_BLOCKPLAYER_CLOSE;
+		return;
+	}
+	if (pVehicle->AutoPilot.m_nCarMission == MISSION_BLOCKCAR_HANDBRAKESTOP){
+		if (((CVector2D)pVehicle->GetMoveSpeed()).MagnitudeSqr() < SQR(0.01f) &&
+		  CVector2D(targetSpeedX, targetSpeedY).MagnitudeSqr() < SQR(0.02f) &&
+		  pVehicle->bIsLawEnforcer){
+			CCarAI::TellOccupantsToLeaveCar(pVehicle);
+			pVehicle->AutoPilot.m_nCruiseSpeed = 0;
+			pVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
+		}
+	}else{
+		if (FindPlayerVehicle() && FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.05f)
+#ifdef FIX_BUGS
+			pVehicle->m_nTimeBlocked += CTimer::GetTimeStepInMilliseconds();
+#else
+			pVehicle->m_nTimeBlocked += 16.66f * CTimer::GetTimeStep(); // very doubtful constant
+#endif
+		else
+			pVehicle->m_nTimeBlocked = 0;
+		if ((FindPlayerVehicle() == nil || FindPlayerVehicle()->IsUpsideDown() ||
+		  FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.05f) &&
+		  pVehicle->m_nTimeBlocked > TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING){
+			if (pVehicle->bIsLawEnforcer && distanceToTargetSqr < SQR(DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK)){
+				CCarAI::TellOccupantsToLeaveCar(pVehicle);
+				pVehicle->AutoPilot.m_nCruiseSpeed = 0;
+				pVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
+			}
+		}
+	}
+}
+
+void CCarCtrl::SteerAIBoatWithPhysicsHeadingForTarget(CBoat* pBoat, float targetX, float targetY, float* pSwerve, float* pAccel, float* pBrake)
+{
+	CVector2D forward(pBoat->GetForward());
+	forward.Normalise();
+	CVector2D distanceToTarget = CVector2D(targetX, targetY) - pBoat->GetPosition();
+	float angleToTarget = CGeneral::GetATanOfXY(distanceToTarget.x, distanceToTarget.y);
+	float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y);
+	float angleDiff = LimitRadianAngle(angleToTarget - angleForward);
+	angleDiff = min(DEFAULT_MAX_STEER_ANGLE, max(-DEFAULT_MAX_STEER_ANGLE, angleDiff));
+	float currentSpeed = pBoat->GetMoveSpeed().Magnitude(); // +0.0f for some reason
+	float speedDiff = pBoat->AutoPilot.m_nCruiseSpeed - currentSpeed;
+	if (speedDiff > 0.0f){
+		float accRemaining = speedDiff / pBoat->AutoPilot.m_nCruiseSpeed;
+		*pAccel = (accRemaining > 0.25f) ? 1.0f : 1.0f - (0.25f - accRemaining) * 4.0f;
+	}else
+		*pAccel = (speedDiff < -5.0f) ? -0.2f : -0.1f;
+	*pBrake = 0.0f;
+	*pSwerve = angleDiff;
+}
 
 bool CCarCtrl::ThisRoadObjectCouldMove(int16 mi)
 {
@@ -1994,9 +2475,6 @@ InjectHook(0x416580, &CCarCtrl::GenerateRandomCars, PATCH_JUMP);
 InjectHook(0x417EC0, &CCarCtrl::ChooseModel, PATCH_JUMP);
 InjectHook(0x418320, &CCarCtrl::RemoveDistantCars, PATCH_JUMP);
 InjectHook(0x418430, &CCarCtrl::PossiblyRemoveVehicle, PATCH_JUMP);
-InjectHook(0x418C10, &CCarCtrl::FindMaximumSpeedForThisCarInTraffic, PATCH_JUMP);
-InjectHook(0x41A590, &CCarCtrl::FindAngleToWeaveThroughTraffic, PATCH_JUMP);
-InjectHook(0x41BA50, &CCarCtrl::PickNextNodeAccordingStrategy, PATCH_JUMP);
 InjectHook(0x41D280, &CCarCtrl::Init, PATCH_JUMP);
 InjectHook(0x41D3B0, &CCarCtrl::ReInit, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h
index f545d492..17dc4bf5 100644
--- a/src/control/CarCtrl.h
+++ b/src/control/CarCtrl.h
@@ -1,5 +1,6 @@
 #pragma once
 #include "PathFind.h"
+#include "Boat.h"
 #include "Vehicle.h"
 
 class CZoneInfo;
@@ -44,7 +45,6 @@ public:
 	static int32 ChooseCarModel(int32 vehclass);
 	static bool JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool);
 	static void JoinCarWithRoadSystem(CVehicle*);
-	static void SteerAICarWithPhysics(CVehicle*);
 	static void UpdateCarOnRails(CVehicle*);
 	static bool MapCouldMoveInThisArea(float x, float y);
 	static void ScanForPedDanger(CVehicle *veh);
@@ -84,14 +84,18 @@ public:
 	static uint8 FindPathDirection(int32, int32, int32);
 	static void Init(void);
 	static void ReInit(void);
+	static float FindSpeedMultiplier(float, float, float, float);
+	static void SteerAICarWithPhysics(CVehicle*);
+	static void SteerAICarWithPhysics_OnlyMission(CVehicle*, float*, float*, float*, bool*);
+	static void SteerAIBoatWithPhysics(CBoat*);
+	static float FindMaxSteerAngle(CVehicle*);
+	static void SteerAICarWithPhysicsFollowPath(CVehicle*, float*, float*, float*, bool*);
+	static void SteerAICarWithPhysicsHeadingForTarget(CVehicle*, CPhysical*, float, float, float*, float*, float*, bool*);
+	static void SteerAICarWithPhysicsTryingToBlockTarget(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
+	static void SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
+	static void SteerAIBoatWithPhysicsHeadingForTarget(CBoat*, float, float, float*, float*, float*);
 	static bool ThisRoadObjectCouldMove(int16);
 
-	static float GetOffsetOfLaneFromCenterOfRoad(int8 lane, CCarPathLink* pLink)
-	{
-		return (lane + ((pLink->numLeftLanes == 0) ? (0.5f - 0.5f * pLink->numRightLanes) :
-			((pLink->numRightLanes == 0) ? (0.5f - 0.5f * pLink->numLeftLanes) : 0.5f))) * LANE_WIDTH;
-	}
-
 	static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
 	{
 		uint32 timeInCurve = CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeEnteredCurve;
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index d3f89154..91e2e0b1 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -75,6 +75,15 @@ struct CCarPathLink
 
 	uint8 bBridgeLights : 1;
 	// more?
+
+	float OneWayLaneOffset()
+	{
+		if (numLeftLanes == 0)
+			return 0.5f - 0.5f * numRightLanes;
+		if (numRightLanes == 0)
+			return 0.5f - 0.5f * numLeftLanes;
+		return 0.5f;
+	}
 };
 
 struct CPathInfoForObject
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index c157786d..65ee2840 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -960,6 +960,7 @@ void CReplay::EmptyReplayBuffer(void)
 {
 	if (Mode == MODE_PLAYBACK)
 		return;
+	Record.m_nOffset = 0;
 	for (int i = 0; i < 8; i++){
 		BufferStatus[i] = REPLAYBUFFER_UNUSED;
 	}
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 8d22606a..8abba646 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -78,7 +78,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
 	m_veh_flagD1 = false;
 	m_veh_flagD2 = false;
 	m_nGunFiringTime = 0;
-	field_214 = 0;
+	m_nTimeBlocked = 0;
 	bLightsOn = false;
 	bVehicleColProcessed = false;
 	m_numPedsUseItAsCover = 0;
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 0a86d4e5..4c4f1767 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -183,7 +183,7 @@ public:
 	float m_fChangeGearTime;
 	uint32 m_nGunFiringTime;    // last time when gun on vehicle was fired (used on boats)
 	uint32 m_nTimeOfDeath;
-	int16 field_214;
+	uint16 m_nTimeBlocked;
 	int16 m_nBombTimer;        // goes down with each frame
 	CEntity *m_pBlowUpEntity;
 	float m_fMapObjectHeightAhead;	// front Z?