From da39624f1c694dbeaefc6762fd6867715cdb77bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?eray=20or=C3=A7unus?= <erayorcunus@gmail.com>
Date: Thu, 8 Oct 2020 00:21:44 +0300
Subject: [PATCH] Pad, BulletInfo, ProjectileInfo, fixes

---
 src/control/Script.cpp           |   2 +-
 src/core/Camera.cpp              |   2 +-
 src/core/EventList.cpp           |   4 +-
 src/core/Frontend.cpp            |  52 +++--
 src/core/Frontend.h              |   6 +-
 src/core/Pad.cpp                 | 348 +++++++++++++++++++++++++------
 src/core/Pad.h                   |   7 +
 src/core/Radar.cpp               |  58 +-----
 src/core/re3.cpp                 |   6 +-
 src/modelinfo/ModelIndices.h     |   3 +
 src/modelinfo/VehicleModelInfo.h |   2 +-
 src/peds/Ped.cpp                 |   5 +-
 src/peds/Ped.h                   |   1 -
 src/save/GenericGameStorage.cpp  |  11 +-
 src/skel/events.cpp              |   2 +
 src/vehicles/Boat.cpp            |  11 +-
 src/vehicles/Vehicle.cpp         |   2 +
 src/vehicles/Vehicle.h           |   2 +
 src/weapons/BulletInfo.cpp       | 160 ++++++++------
 src/weapons/ProjectileInfo.cpp   | 239 +++++++++++++--------
 20 files changed, 608 insertions(+), 315 deletions(-)

diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 95e93b6c..aa4e109f 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -12020,7 +12020,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command)
 		script_assert(pVehicle);
 		bool bIsBurst = false;
 		CBike* pBike = (CBike*)pVehicle;
-		if (pVehicle->m_vehType == VEHICLE_APPEARANCE_BIKE) {
+		if (pVehicle->IsBike()) {
 			if (ScriptParams[1] == 4) {
 				for (int i = 0; i < 2; i++) {
 					if (pBike->m_wheelStatus[i] == WHEEL_STATUS_BURST)
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 704e77b8..2fa81d24 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -1749,7 +1749,7 @@ CCamera::CamControl(void)
 
 	if(PrevMode != Cams[ActiveCam].Mode || switchedFromObbe ||
 	   Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED || Cams[ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING)
-		if(CPad::GetPad(0)->CycleCameraModeUpJustDown() &&
+		if(CPad::GetPad(0)->CycleCameraModeJustDown() &&
 		   !CReplay::IsPlayingBack() &&
 		   (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
 		   !m_WideScreenOn &&
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
index 7eb1e186..b22ddcb2 100644
--- a/src/core/EventList.cpp
+++ b/src/core/EventList.cpp
@@ -10,6 +10,8 @@
 #include "main.h"
 #include "Accident.h"
 
+// --MIAMI: file done
+
 int32 CEventList::ms_nFirstFreeSlotIndex;
 CEvent gaEvent[NUMEVENTS];
 
@@ -57,6 +59,7 @@ CEventList::Update(void)
 	}
 }
 
+// ok
 void
 CEventList::RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout)
 {
@@ -195,7 +198,6 @@ CEventList::FindClosestEvent(eEventType type, CVector posn, int32 *event)
 	return found;
 }
 
-// --MIAMI: Done
 void
 CEventList::ReportCrimeForEvent(eEventType type, size_t crimeId, bool copsDontCare)
 {
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index eee8b4b2..59649e93 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -352,7 +352,7 @@ CMenuManager::CMenuManager()
 	m_PrefsUseVibration = 0;
 	m_PrefsShowHud = 1;
 	m_PrefsRadarMode = 0;
-	field_10 = 0;
+	m_DisplayControllerOnFoot = false;
 	m_bShutDownFrontEndRequested = false;
 	m_bStartUpFrontEndRequested = false;
 	pEditString = nil;
@@ -950,6 +950,13 @@ CMenuManager::DrawStandardMenus(bool activeScreen)
 						break;
 					}
 					break;
+				// This one is still in enum and ProcessOnOffMenuOptions, but removed from other places
+				case MENUACTION_CTRLDISPLAY:
+					if (m_DisplayControllerOnFoot)
+						rightText = TheText.Get("FEC_ONF");
+					else
+						rightText = TheText.Get("FEC_INC");
+					break;
 #endif
 				case MENUACTION_FRAMESYNC:
 					rightText = TheText.Get(m_PrefsVsyncDisp ? "FEM_ON" : "FEM_OFF");
@@ -4206,6 +4213,7 @@ CMenuManager::ProcessUserInput(uint8 goDown, uint8 goUp, uint8 optionSelected, u
 	}
 }
 
+// --MIAMI: Done
 void
 CMenuManager::ProcessOnOffMenuOptions()
 {
@@ -4213,78 +4221,78 @@ CMenuManager::ProcessOnOffMenuOptions()
 #ifdef LEGACY_MENU_OPTIONS
 	case MENUACTION_CTRLVIBRATION:
 		m_PrefsUseVibration = !m_PrefsUseVibration;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		break;
 	case MENUACTION_CTRLCONFIG:
 		CPad::GetPad(0)->Mode++;
 		if (CPad::GetPad(0)->Mode > 3)
 			CPad::GetPad(0)->Mode = 0;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		break;
 #endif
+	case MENUACTION_INVERTPADY:
+		CPad::bInvertLook4Pad = !CPad::bInvertLook4Pad;
+		SaveSettings(); // FIX: Why don't SaveSettings? Because of it's an hidden option? :(
+		break;
+	case MENUACTION_CTRLDISPLAY:
+		m_DisplayControllerOnFoot = !m_DisplayControllerOnFoot;
+		break;
 	case MENUACTION_FRAMESYNC:
 		m_PrefsVsyncDisp = !m_PrefsVsyncDisp;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
-		SaveSettings();
+		SaveSettings(); // FIX: Again... This makes me very unhappy
 		break;
 	case MENUACTION_FRAMELIMIT:
 		m_PrefsFrameLimiter = !m_PrefsFrameLimiter;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		SaveSettings();
 		break;
 	case MENUACTION_TRAILS:
 		CMBlur::BlurOn = !CMBlur::BlurOn;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		SaveSettings();
-		if (CMBlur::BlurOn)
-			CMBlur::MotionBlurOpen(Scene.camera);
-		else
-			CMBlur::MotionBlurClose();
 		break;
 	case MENUACTION_SUBTITLES:
 		m_PrefsShowSubtitles = !m_PrefsShowSubtitles;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		SaveSettings();
 		break;
 #ifndef ASPECT_RATIO_SCALE
 	case MENUACTION_WIDESCREEN:
 		m_PrefsUseWideScreen = !m_PrefsUseWideScreen;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		SaveSettings();
 		break;
 #endif
+	case MENUACTION_LEGENDS:
+		m_PrefsShowLegends = !m_PrefsShowLegends;
+		break;
+	case MENUACTION_HUD:
+		m_PrefsShowHud = !m_PrefsShowHud;
+		SaveSettings();
+		break;
+#ifdef LEGACY_MENU_OPTIONS
 	case MENUACTION_SETDBGFLAG:
 		CTheScripts::InvertDebugFlag();
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		break;
 	case MENUACTION_SWITCHBIGWHITEDEBUGLIGHT:
 		gbBigWhiteDebugLightSwitchedOn = !gbBigWhiteDebugLightSwitchedOn;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		break;
 	case MENUACTION_COLLISIONPOLYS:
 		gbShowCollisionPolys = !gbShowCollisionPolys;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		break;
+#endif
 	case MENUACTION_SHOWHEADBOB:
 		TheCamera.m_bHeadBob = !TheCamera.m_bHeadBob;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		SaveSettings();
 		break;
 	case MENUACTION_INVVERT:
 		MousePointerStateHelper.bInvertVertically = !MousePointerStateHelper.bInvertVertically;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		SaveSettings();
 		break;
 	case MENUACTION_DYNAMICACOUSTIC:
 		m_PrefsDMA = !m_PrefsDMA;
 		DMAudio.SetDynamicAcousticModelingStatus(m_PrefsDMA);
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
 		SaveSettings();
 		break;
 	case MENUACTION_MOUSESTEER:
-		CVehicle::m_bDisableMouseSteering = !CVehicle::m_bDisableMouseSteering;
-		DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
-		SaveSettings();
+		if (m_ControlMethod == CONTROL_STANDARD) {
+			CVehicle::m_bDisableMouseSteering = !CVehicle::m_bDisableMouseSteering;
+			SaveSettings();
+		}
 		break;
 	}
 }
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 6cd58e7d..0dab83a4 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -207,8 +207,8 @@ enum eMenuAction
 	MENUACTION_YES,
 	MENUACTION_NO,
 	MENUACTION_CHANGEMENU,
-	MENUACTION_UNK5,
 	MENUACTION_INVERTPADY,
+	MENUACTION_CTRLDISPLAY,
 	MENUACTION_FRAMESYNC,
 	MENUACTION_FRAMELIMIT,
 	MENUACTION_TRAILS,
@@ -466,7 +466,7 @@ public:
 	bool m_PrefsUseVibration;
 	bool m_PrefsShowHud;
 	int32 m_PrefsRadarMode;
-	uint8 field_10;
+	bool m_DisplayControllerOnFoot;
 	bool m_bShutDownFrontEndRequested;
 	bool m_bStartUpFrontEndRequested;
 	int32 m_KeyPressedCode;
@@ -702,4 +702,4 @@ VALIDATE_SIZE(CMenuManager, 0x688);
 extern CMenuManager FrontEndMenuManager;
 extern CMenuScreen aScreens[];
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index 36e14e55..785927ce 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -54,6 +54,8 @@
 #include "libpad.h"
 #endif
 
+// --MIAMI: file done except Mobile(see TODOs) and PS2 stuff
+
 CPad Pads[MAX_PADS];
 #ifdef GTA_PS2
 u_long128 pad_dma_buf[scePadDmaBufferMax] __attribute__((aligned(64)));
@@ -66,7 +68,9 @@ bool CPad::bDisplayNoControllerMessage;
 bool CPad::bObsoleteControllerMessage;
 bool CPad::bOldDisplayNoControllerMessage;
 bool CPad::m_bMapPadOneToPadTwo;
+bool CPad::m_bDebugCamPCOn;
 bool CPad::bHasPlayerCheated;
+bool CPad::bInvertLook4Pad;
 #ifdef GTA_PS2
 unsigned char act_direct[6];
 unsigned char act_align[6];
@@ -93,6 +97,74 @@ extern bool gbFastTime;
 extern bool gGravityCheat;
 #endif
 
+void SpecialCarCheats()
+{
+	if ( !CVehicle::bCheat9 )
+	{
+		((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_INFERNUS))->m_wheelScale *= 1.3f;
+		((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_CHEETAH))->m_wheelScale *= 1.3f;
+		((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_PHEONIX))->m_wheelScale *= 1.3f;
+		((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_DELUXO))->m_wheelScale *= 1.3f;
+		mod_HandlingManager.GetHandlingData(HANDLING_LANDSTAL)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_PATRIOT)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_BOBCAT)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_BFINJECT)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_RANCHER)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_DESPERAD)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_DELUXO)->Transmission.fEngineAcceleration *= 2.0f;
+
+		mod_HandlingManager.GetHandlingData(HANDLING_BAGGAGE)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_BAGGAGE)->Transmission.fMaxVelocity *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_BAGGAGE)->Transmission.InitGearRatios();
+
+		mod_HandlingManager.GetHandlingData(HANDLING_GOLFCART)->Transmission.fEngineAcceleration *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_GOLFCART)->Transmission.fMaxVelocity *= 2.0f;
+		mod_HandlingManager.GetHandlingData(HANDLING_GOLFCART)->Transmission.InitGearRatios();
+
+		mod_HandlingManager.GetHandlingData(HANDLING_STINGER)->fCollisionDamageMultiplier *= 0.25f;
+		mod_HandlingManager.GetHandlingData(HANDLING_STINGER)->fMass *= 2.5f;
+		mod_HandlingManager.GetHandlingData(HANDLING_STINGER)->fTurnMass *= 4.0f;
+
+		mod_HandlingManager.GetHandlingData(HANDLING_BANSHEE)->fCollisionDamageMultiplier *= 0.25f;
+		mod_HandlingManager.GetHandlingData(HANDLING_BANSHEE)->fMass *= 2.5f;
+		mod_HandlingManager.GetHandlingData(HANDLING_BANSHEE)->fTurnMass *= 4.0f;
+
+		mod_HandlingManager.GetHandlingData(HANDLING_SABRETUR)->fCollisionDamageMultiplier *= 0.25f;
+		mod_HandlingManager.GetHandlingData(HANDLING_SABRETUR)->fMass *= 2.5f;
+		mod_HandlingManager.GetHandlingData(HANDLING_SABRETUR)->fTurnMass *= 4.0f;
+
+		mod_HandlingManager.GetHandlingData(HANDLING_COMET)->fCollisionDamageMultiplier *= 0.25f;
+		mod_HandlingManager.GetHandlingData(HANDLING_COMET)->fMass *= 2.5f;
+		mod_HandlingManager.GetHandlingData(HANDLING_COMET)->fTurnMass *= 4.0f;
+
+		mod_HandlingManager.GetHandlingData(HANDLING_DELUXO)->fCollisionDamageMultiplier *= 0.25f;
+		mod_HandlingManager.GetHandlingData(HANDLING_DELUXO)->fMass *= 2.5f;
+		mod_HandlingManager.GetHandlingData(HANDLING_DELUXO)->fTurnMass *= 4.0f;
+		CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+		CVehicle::bCheat9 = true;
+		CPad::bHasPlayerCheated = true;
+	}
+}
+
+void PickUpChicksCheat()
+{
+	if ( FindPlayerVehicle() && (FindPlayerVehicle()->IsCar() || FindPlayerVehicle()->IsBike()) )
+	{
+		CVehicle *vehicle = FindPlayerVehicle();
+		if ( FindPlayerVehicle()->m_vehType == 5 )
+		{
+			if ( vehicle->pPassengers[0] )
+				vehicle->pPassengers[0]->SetObjective(OBJECTIVE_LEAVE_CAR, vehicle);
+		}
+		CPed* someoneElse = (CPed*)CWorld::TestSphereAgainstWorld(vehicle->GetPosition(), 6.0f, FindPlayerPed(), false, false, true, false, false, false);
+		if ( someoneElse && someoneElse->m_nPedState != PED_DRIVING )
+		{
+			CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
+			someoneElse->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, vehicle);
+		}
+	}
+}
+
 void WeaponCheat1()
 {
 	CHud::SetHelpMessage(TheText.Get("CHEAT2"), true);
@@ -127,6 +199,11 @@ void WeaponCheat1()
 	CStreaming::SetModelIsDeletable(MI_RUGER);
 	CStreaming::SetModelIsDeletable(MI_SNIPERRIFLE);
 	CStreaming::SetModelIsDeletable(MI_FLAMETHROWER);
+#ifdef MOBILE_IMPROVEMENTS
+	if (FindPlayerVehicle()) {
+		FindPlayerPed()->RemoveWeaponWhenEnteringVehicle();
+	}
+#endif
 }
 
 void WeaponCheat2()
@@ -162,6 +239,11 @@ void WeaponCheat2()
 	CStreaming::SetModelIsDeletable(MI_M4);
 	CStreaming::SetModelIsDeletable(MI_LASERSCOPE);
 	CStreaming::SetModelIsDeletable(MI_ROCKETLAUNCHER);
+#ifdef MOBILE_IMPROVEMENTS
+	if (FindPlayerVehicle()) {
+		FindPlayerPed()->RemoveWeaponWhenEnteringVehicle();
+	}
+#endif
 }
 
 void WeaponCheat3()
@@ -197,6 +279,12 @@ void WeaponCheat3()
 	CStreaming::SetModelIsDeletable(MI_LASERSCOPE);
 	CStreaming::SetModelIsDeletable(MI_MINIGUN);
 	CStreaming::SetModelIsDeletable(MI_MINIGUN2);
+
+#ifdef MOBILE_IMPROVEMENTS
+	if (FindPlayerVehicle()) {
+		FindPlayerPed()->RemoveWeaponWhenEnteringVehicle();
+	}
+#endif
 }
 
 void HealthCheat()
@@ -213,6 +301,7 @@ void HealthCheat()
 	}
 }
 
+// TODO(Miami): this is HELLA different on mobile, although it mostly has debug oriented things like player exiting it's current car and enters spawned one etc.
 void VehicleCheat(int model)
 {
 	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
@@ -232,7 +321,7 @@ void VehicleCheat(int model)
 #ifdef FIX_BUGS
 		CAutomobile* vehicle = new CAutomobile(model, RANDOM_VEHICLE);
 #else
-		CAutomobile* vehicle = new CAutomobile(MI_RHINO, MISSION_VEHICLE);
+		CAutomobile* vehicle = new CAutomobile(model, MISSION_VEHICLE);
 #endif
 		if (vehicle != nil) {
 			CVector pos = ThePaths.m_pathNodes[node].GetPosition();
@@ -249,6 +338,7 @@ void VehicleCheat(int model)
 	CPad::bHasPlayerCheated = true;
 }
 
+
 void BlowUpCarsCheat()
 {
 	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
@@ -262,7 +352,8 @@ void BlowUpCarsCheat()
 
 void ChangePlayerCheat()
 {
-	int modelId;
+	// I don't know wtf is going on in here...
+	int modelId, anotherModelId;
 
 	if (FindPlayerPed()->IsPedInControl() && CModelInfo::GetModelInfo("player", nil)) {
 		CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
@@ -270,21 +361,22 @@ void ChangePlayerCheat()
 		AssocGroupId AnimGrp = ped->m_animGroup;
 		do
 		{
-			do
-				modelId = CGeneral::GetRandomNumberInRange(0, MI_WFYG2+1);
-			while (!CModelInfo::GetModelInfo(modelId));
-		} while (modelId == MI_TAXI_D);
+			do {
+				modelId = CGeneral::GetRandomNumberInRange(0, MI_PGA);
+				anotherModelId = modelId+1;
+			} while (!CModelInfo::GetModelInfo(anotherModelId));
+		} while (anotherModelId >= MI_SPECIAL01 && anotherModelId <= MI_SPECIAL04 || modelId == MI_TAXI_D);
 
-		uint8 flags = CStreaming::ms_aInfoForModel[modelId].m_flags;
+		uint8 flags = CStreaming::ms_aInfoForModel[anotherModelId].m_flags;
 		ped->DeleteRwObject();
-		CStreaming::RequestModel(modelId, STREAMFLAGS_DEPENDENCY| STREAMFLAGS_DONT_REMOVE);
+		CStreaming::RequestModel(anotherModelId, STREAMFLAGS_DEPENDENCY| STREAMFLAGS_DONT_REMOVE);
 		CStreaming::LoadAllRequestedModels(false);
 		ped->m_modelIndex = -1;
-		ped->SetModelIndex(modelId);
+		ped->SetModelIndex(anotherModelId);
 		ped->m_animGroup = AnimGrp;
-		if (modelId != MI_PLAYER) {
+		if (modelId != -1) {
 			if (!(flags & STREAMFLAGS_DONT_REMOVE))
-				CStreaming::SetModelIsDeletable(modelId);
+				CStreaming::SetModelIsDeletable(anotherModelId);
 		}
 	}
 }
@@ -426,11 +518,6 @@ void StrongGripCheat()
 	CPad::bHasPlayerCheated = true;
 }
 
-void NastyLimbsCheat()
-{
-	CPed::bNastyLimbsCheat = !CPed::bNastyLimbsCheat;
-}
-
 void FannyMagnetCheat()
 {
 	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
@@ -578,6 +665,7 @@ void FlyingFishCheat(void)
 {
 	CHud::SetHelpMessage(TheText.Get("CHEAT1"), true);
 	CVehicle::bCheat8 = !CVehicle::bCheat8;
+	CPad::bHasPlayerCheated = true;
 }
 
 void DoShowChaseStatCheat(void) {
@@ -655,6 +743,8 @@ void CPad::Initialise(void)
 	bObsoleteControllerMessage	   = false;
 	bOldDisplayNoControllerMessage = false;
 	bDisplayNoControllerMessage	   = false;
+	m_bMapPadOneToPadTwo = false;
+	m_bDebugCamPCOn = false;
 }
 #endif
 
@@ -687,9 +777,9 @@ void CPad::Clear(bool bResetPlayerControls)
 	if ( bResetPlayerControls )
 		DisablePlayerControls = PLAYERCONTROL_ENABLED;
 
+	JustOutOfFrontend = 0;
 	bApplyBrakes = false;
 
-
 	for ( int32 i = 0; i < HORNHISTORY_SIZE; i++ )
 		bHornHistory[i] = false;
 
@@ -715,6 +805,14 @@ void CPad::ClearMouseHistory()
 	OldMouseControllerState.Clear();
 }
 
+// unused
+void CPad::ClearKeyBoardHistory()
+{
+	NewKeyState.Clear();
+	OldKeyState.Clear();
+	TempKeyState.Clear();
+}
+
 CMouseControllerState::CMouseControllerState()
 {
 	LMB = 0;
@@ -1113,9 +1211,6 @@ void CPad::AddToCheatString(char c)
 	else if ( !_CHEATCMP("T33L1413") )
 		StrongGripCheat();
 
-	// "S1CD13TR1X"		-	SQUARE L1 CIRCLE DOWN L1 R1 TRIANGLE RIGHT L1 CROSS
-	else if ( !_CHEATCMP("X1RT31DC1S") )
-		NastyLimbsCheat();
 #undef _CHEATCMP
 }
 #endif
@@ -1132,6 +1227,7 @@ int Cheat_strncmp(char* sourceStr, char* origCheatStr)
 	return 0;
 }
 
+// TODO(Miami): Mobile has changed some of the cheats to include debugging things
 void CPad::AddToPCCheatString(char c)
 {
 	for (int32 i = ARRAY_SIZE(KeyBoardCheatString) - 2; i >= 0; i--)
@@ -1406,6 +1502,16 @@ void CPad::AddToPCCheatString(char c)
 		KeyBoardCheatString[0] = ' ';
 		BackToTheFuture();
 	}
+	// LOADSOFLITTLETHINGS
+	else if (!Cheat_strncmp(KeyBoardCheatString, "VLUJUoHSU_VTMo`J]bV")) {
+		KeyBoardCheatString[0] = ' ';
+		SpecialCarCheats();
+	}
+	// HOPINGIRL
+	else if (!Cheat_strncmp(KeyBoardCheatString, "OWPH[dSVI")) {
+		KeyBoardCheatString[0] = ' ';
+		PickUpChicksCheat();
+	}
 	//CERTAINDEATH
 	else if (!Cheat_strncmp(KeyBoardCheatString, "KYHFQiLHU]RK")) {
 		KeyBoardCheatString[0] = ' ';
@@ -1422,10 +1528,6 @@ void CPad::AddToPCCheatString(char c)
 		FannyMagnetCheat();
 	}
 
-	// "NASTYLIMBSCHEAT"
-	if (!_CHEATCMP("TAEHCSBMILYTSAN"))
-		NastyLimbsCheat();
-
 #ifdef KANGAROO_CHEAT
 	// "KANGAROO"
 	if (!_CHEATCMP("OORAGNAK"))
@@ -1879,6 +1981,9 @@ void CPad::Update(int16 pad)
 
 	if ( !bDisplayNoControllerMessage )
 		CGame::bDemoMode = false;
+
+	if ( JustOutOfFrontend != 0 )
+		--JustOutOfFrontend;
 }
 
 void CPad::DoCheats(void)
@@ -1963,7 +2068,6 @@ CPad *CPad::GetPad(int32 pad)
 #define CURMODE (Mode)
 #endif
 
-
 int16 CPad::GetSteeringLeftRight(void)
 {
 	if ( ArePlayerControlsDisabled() )
@@ -2126,7 +2230,6 @@ int16 CPad::GetPedWalkLeftRight(void)
 	return 0;
 }
 
-
 int16 CPad::GetPedWalkUpDown(void)
 {
 	if ( ArePlayerControlsDisabled() )
@@ -2190,6 +2293,36 @@ int16 CPad::GetAnalogueUpDown(void)
 	return 0;
 }
 
+int16 CPad::GetAnalogueLeftRight(void)
+{
+	switch (CURMODE)
+	{
+		case 0:
+		case 2:
+		{
+			int16 axis = NewState.LeftStickX;
+			int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2;
+
+			if ( Abs(axis) > Abs(dpad) )
+				return axis;
+			else
+				return dpad;
+
+			break;
+		}
+
+		case 1:
+		case 3:
+		{
+			return NewState.LeftStickX;
+
+			break;
+		}
+	}
+
+	return 0;
+}
+
 bool CPad::GetLookLeft(void)
 {
 	if ( ArePlayerControlsDisabled() )
@@ -2301,7 +2434,6 @@ bool CPad::HornJustDown(void)
 	return false;
 }
 
-
 bool CPad::GetCarGunFired(void)
 {
 	if ( ArePlayerControlsDisabled() )
@@ -2432,6 +2564,10 @@ bool CPad::GetExitVehicle(void)
 	if ( ArePlayerControlsDisabled() )
 		return false;
 
+
+	if ( JustOutOfFrontend != 0 )
+		return false;
+
 	switch (CURMODE)
 	{
 		case 0:
@@ -2459,6 +2595,9 @@ bool CPad::ExitVehicleJustDown(void)
 	if ( ArePlayerControlsDisabled() )
 		return false;
 
+	if ( JustOutOfFrontend != 0 )
+		return false;
+
 	switch (CURMODE)
 	{
 		case 0:
@@ -2585,6 +2724,53 @@ int16 CPad::GetAccelerate(void)
 	return 0;
 }
 
+bool CPad::CycleCameraModeJustDown(void)
+{
+	bool result;
+	switch (CURMODE)
+	{
+		case 0:
+		case 2:
+		case 3:
+		{
+			result = !!(NewState.Select && !OldState.Select);
+
+			break;
+		}
+
+		case 1:
+		{
+			result = !!(NewState.DPadUp && !OldState.DPadUp);
+
+			break;
+		}
+		default:
+		{
+			result = false;
+			break;
+		}
+	}
+
+	if (!result)
+	{
+		switch (CURMODE)
+		{
+			case 1:
+			{
+				result = !!(NewState.DPadDown && !OldState.DPadDown);
+				break;
+			}
+			default:
+			{
+				result = false;
+				break;
+			}
+		}
+	}
+
+	return result;
+}
+
 bool CPad::CycleCameraModeUpJustDown(void)
 {
 	switch (CURMODE)
@@ -2672,7 +2858,6 @@ bool CPad::ChangeStationJustDown(void)
 	return false;
 }
 
-
 bool CPad::CycleWeaponLeftJustDown(void)
 {
 	if ( ArePlayerControlsDisabled() )
@@ -2831,23 +3016,23 @@ bool CPad::ShiftTargetRightJustDown(void)
 	if ( ArePlayerControlsDisabled() )
 		return false;
 
-	return !!(NewState.RightShoulder2 && !OldState.RightShoulder2);
+	return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1) || !!(NewState.RightShoulder2 && !OldState.RightShoulder2);
 }
 
 bool CPad::GetAnaloguePadUp(void)
 {
 	static int16 oldfStickY = 0;
 
-	int16 Y = CPad::GetPad(0)->GetAnalogueUpDown();
+	int16 leftStickY = CPad::GetPad(0)->GetLeftStickY();
 
-	if ( Y < 0 && oldfStickY >= 0 )
+	if ( leftStickY < -15 && oldfStickY >= -5 )
 	{
-		oldfStickY = Y;
+		oldfStickY = leftStickY;
 		return true;
 	}
 	else
 	{
-		oldfStickY = Y;
+		oldfStickY = leftStickY;
 		return false;
 	}
 }
@@ -2856,16 +3041,16 @@ bool CPad::GetAnaloguePadDown(void)
 {
 	static int16 oldfStickY = 0;
 
-	int16 Y = CPad::GetPad(0)->GetAnalogueUpDown();
+	int16 leftStickY = CPad::GetPad(0)->GetLeftStickY();
 
-	if ( Y > 0 && oldfStickY <= 0 )
+	if ( leftStickY > 15 && oldfStickY <= 5 )
 	{
-		oldfStickY = Y;
+		oldfStickY = leftStickY;
 		return true;
 	}
 	else
 	{
-		oldfStickY = Y;
+		oldfStickY = leftStickY;
 		return false;
 	}
 }
@@ -2874,16 +3059,16 @@ bool CPad::GetAnaloguePadLeft(void)
 {
 	static int16 oldfStickX = 0;
 
-	int16 X = CPad::GetPad(0)->GetPedWalkLeftRight();
+	int16 leftStickX = CPad::GetPad(0)->GetLeftStickX();
 
-	if ( X < 0 && oldfStickX >= 0 )
+	if ( leftStickX < -15 && oldfStickX >= -5 )
 	{
-		oldfStickX = X;
+		oldfStickX = leftStickX;
 		return true;
 	}
 	else
 	{
-		oldfStickX = X;
+		oldfStickX = leftStickX;
 		return false;
 	}
 }
@@ -2892,16 +3077,16 @@ bool CPad::GetAnaloguePadRight(void)
 {
 	static int16 oldfStickX = 0;
 
-	int16 X = CPad::GetPad(0)->GetPedWalkLeftRight();
+	int16 leftStickX = CPad::GetPad(0)->GetLeftStickX();
 
-	if ( X > 0 && oldfStickX <= 0 )
+	if ( leftStickX > 15 && oldfStickX <= 5 )
 	{
-		oldfStickX = X;
+		oldfStickX = leftStickX;
 		return true;
 	}
 	else
 	{
-		oldfStickX = X;
+		oldfStickX = leftStickX;
 		return false;
 	}
 }
@@ -2914,7 +3099,7 @@ bool CPad::GetAnaloguePadLeftJustUp(void)
 
 	if ( X == 0 && oldfStickX < 0 )
 	{
-		oldfStickX = X;
+		oldfStickX = 0;
 
 		return true;
 	}
@@ -2934,7 +3119,7 @@ bool CPad::GetAnaloguePadRightJustUp(void)
 
 	if ( X == 0 && oldfStickX > 0 )
 	{
-		oldfStickX = X;
+		oldfStickX = 0;
 
 		return true;
 	}
@@ -3040,23 +3225,35 @@ int16 CPad::SniperModeLookLeftRight(void)
 	int16 axis = NewState.LeftStickX;
 	int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2;
 
-	if ( Abs(axis) > Abs(dpad) )
-		return axis;
-	else
+	if ( Abs(axis) > Abs(dpad) ) {
+		if ( Abs(axis) > 35.0f ) {
+		  return (axis > 0.f ? axis - 35.f : axis + 35.f) * 1.3763441f;
+		} else {
+		  return 0;
+		}
+	} else
 		return dpad;
 }
 
 int16 CPad::SniperModeLookUpDown(void)
 {
 	int16 axis = NewState.LeftStickY;
-#ifdef FIX_BUGS
-	axis = -axis;
-#endif
-	int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2;
+	int16 dpad;
 
-	if ( Abs(axis) > Abs(dpad) )
-		return axis;
-	else
+	if (CPad::bInvertLook4Pad) {
+		axis = -axis;
+		dpad = (NewState.DPadDown - NewState.DPadUp) / 2;
+	} else {
+		dpad = (NewState.DPadUp - NewState.DPadDown) / 2;
+	}
+
+	if ( Abs(axis) > Abs(dpad) ) {
+	    if ( Abs(axis) > 35.0f ) {
+	      return (axis > 0.f ? axis - 35.f : axis + 35.f) * 1.3763441f;
+	    } else {
+	      return 0;
+	    }
+	} else
 		return dpad;
 }
 
@@ -3079,9 +3276,8 @@ int16 CPad::LookAroundUpDown(void)
 {
 	int16 axis = GetPad(0)->NewState.RightStickY;
 
-#ifdef FIX_BUGS
-	axis = -axis;
-#endif
+	if (CPad::bInvertLook4Pad)
+		axis = -axis;
 
 	if ( Abs(axis) > 85 && !GetLookBehindForPed() )
 		return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) )
@@ -3094,7 +3290,6 @@ int16 CPad::LookAroundUpDown(void)
 	return 0;
 }
 
-
 void CPad::ResetAverageWeapon(void)
 {
 	AverageWeapon = GetWeapon();
@@ -3103,6 +3298,9 @@ void CPad::ResetAverageWeapon(void)
 
 void CPad::PrintErrorMessage(void)
 {
+	if (TheCamera.m_WideScreenOn)
+		return;
+
 	if ( bDisplayNoControllerMessage && !CGame::playingIntro && !FrontEndMenuManager.m_bMenuActive )
 	{
 		CSprite2d::DrawRect(CRect(SCREEN_STRETCH_X(20.0f), SCREEN_SCALE_FROM_BOTTOM(130.0f), SCREEN_STRETCH_FROM_RIGHT(20.0f), SCREEN_SCALE_Y(140.0f)), CRGBA(50, 50, 50, 210));
@@ -3153,26 +3351,30 @@ void CPad::ResetCheats(void)
 {
 	CWeather::ReleaseWeather();
 
+	gbFastTime = false;
 	CPopulation::ms_bGivePedsWeapons = false;
-
-	CPed::bNastyLimbsCheat = false;
-	CPed::bFannyMagnetCheat = false;
-	CPed::bPedCheat2 = false;
-	CPed::bPedCheat3 = false;
+	CTimer::SetTimeScale(1.0f);
 
 	CVehicle::bWheelsOnlyCheat = false;
 	CVehicle::bAllDodosCheat = false;
 	CVehicle::bCheat3 = false;
 	CVehicle::bCheat4 = false;
 	CVehicle::bCheat5 = false;
+	CVehicle::bAllTaxisHaveNitro = false;
+	CVehicle::bHoverCheat = false;
 	CVehicle::bCheat8 = false;
+	CVehicle::bCheat9 = false;
+	CVehicle::bCheat10 = false;
 	gbBlackCars = false;
 	gbPinkCars = false;
+
 	CCarCtrl::bMadDriversCheat = false;
 	CTrafficLights::bGreenLightsCheat = false;
 	CStats::ShowChaseStatOnScreen = 0;
-	gbFastTime = false;
-	CTimer::SetTimeScale(1.0f);
+	CPed::bNastyLimbsCheat = false;
+	CPed::bFannyMagnetCheat = false;
+	CPed::bPedCheat3 = false;
+
 }
 
 char *CPad::EditString(char *pStr, int32 nSize)
@@ -3377,3 +3579,13 @@ int32 *CPad::EditCodesForControls(int32 *pRsKeys, int32 nSize)
 
 	return pRsKeys;
 }
+
+void CPad::FixPadsAfterSave(void)
+{
+	UpdatePads();
+	if ( bObsoleteControllerMessage )
+	{
+		bObsoleteControllerMessage = false;
+		GetPad(0)->Phase = 0;
+	}
+}
\ No newline at end of file
diff --git a/src/core/Pad.h b/src/core/Pad.h
index cde2d3c5..01f5bb9b 100644
--- a/src/core/Pad.h
+++ b/src/core/Pad.h
@@ -158,6 +158,7 @@ public:
 	uint8 ShakeFreq;
 	bool bHornHistory[HORNHISTORY_SIZE];
 	uint8 iCurrHornHistory;
+	int8 JustOutOfFrontend;
 	int8 bApplyBrakes;
 	char CheatString[12];
 	int32 LastTimeTouched;
@@ -174,7 +175,9 @@ public:
 	static bool bObsoleteControllerMessage;
 	static bool bOldDisplayNoControllerMessage;
 	static bool m_bMapPadOneToPadTwo;
+	static bool m_bDebugCamPCOn;
 	static bool bHasPlayerCheated;
+	static bool bInvertLook4Pad;
 	
 	static CKeyboardState OldKeyState;
 	static CKeyboardState NewKeyState;
@@ -190,6 +193,7 @@ public:
 #endif
 	void Clear(bool bResetPlayerControls);
 	void ClearMouseHistory();
+	void ClearKeyBoardHistory();
 	void UpdateMouse();
 	CControllerState ReconcileTwoControllersInput(CControllerState const &State1, CControllerState const &State2);
 	void StartShake(int16 nDur, uint8 nFreq);
@@ -219,6 +223,7 @@ public:
 	int16 GetPedWalkLeftRight(void);
 	int16 GetPedWalkUpDown(void);
 	int16 GetAnalogueUpDown(void);
+	int16 GetAnalogueLeftRight(void);
 	bool GetLookLeft(void);
 	bool GetLookRight(void);
 	bool GetLookBehindForCar(void);
@@ -234,6 +239,7 @@ public:
 	int32 GetWeapon(void);
 	bool WeaponJustDown(void);
 	int16 GetAccelerate(void);
+	bool CycleCameraModeJustDown(void);
 	bool CycleCameraModeUpJustDown(void);
 	bool CycleCameraModeDownJustDown(void);
 	bool ChangeStationJustDown(void);
@@ -261,6 +267,7 @@ public:
 	int16 LookAroundLeftRight(void);
 	int16 LookAroundUpDown(void);
 	void ResetAverageWeapon(void);
+	static void FixPadsAfterSave(void);
 	static void PrintErrorMessage(void);
 	static void ResetCheats(void);
 	static char *EditString(char *pStr, int32 nSize);
diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp
index b9fc369d..5317040f 100644
--- a/src/core/Radar.cpp
+++ b/src/core/Radar.cpp
@@ -750,9 +750,7 @@ void CRadar::DrawBlips()
 void CRadar::DrawMap()
 {
 	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
-#if 1 // from VC
 		CalculateCachedSinCos();
-#endif
 		if (FindPlayerVehicle()) {
 			float speed = FindPlayerSpeed().Magnitude();
 			if (speed < RADAR_MIN_SPEED)
@@ -1366,33 +1364,8 @@ void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &
 void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
 {
 	float s, c;
-#if 1
 	s = -cachedSin;
 	c = cachedCos;
-#else
-	// Original code
-
-	s = -Sin(TheCamera.GetForward().Heading());
-	c = Cos(TheCamera.GetForward().Heading());
-
-	if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) {
-		s = 0.0f;
-		c = 1.0f;
-	}
-	else if (TheCamera.GetLookDirection() != LOOKING_FORWARD) {
-		CVector forward;
-
-		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) {
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
-			forward.Normalise();	// a bit useless...
-		}
-		else
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
-
-		s = -Sin(forward.Heading());
-		c = Cos(forward.Heading());
-	}
-#endif
 
 	out.x = s * in.y + c * in.x;
 	out.y = c * in.y - s * in.x;
@@ -1419,35 +1392,8 @@ void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &i
 void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
 {
 	float s, c;
-#if 1
 	s = cachedSin;
 	c = cachedCos;
-#else
-	// Original code
-
-	float s, c;
-	if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOP_DOWN_PED) {
-		s = 0.0f;
-		c = 1.0f;
-	}
-	else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) {
-		s = Sin(TheCamera.GetForward().Heading());
-		c = Cos(TheCamera.GetForward().Heading());
-	}
-	else {
-		CVector forward;
-
-		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) {
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
-			forward.Normalise();	// a bit useless...
-		}
-		else
-			forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
-
-		s = Sin(forward.Heading());
-		c = Cos(forward.Heading());
-	}
-#endif
 
 	float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_radarRange);
 	float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_radarRange);
@@ -1534,10 +1480,10 @@ CRadar::ToggleTargetMarker(float x, float y)
 			if (!ms_RadarTrace[nextBlip].m_bInUse)
 				break;
 		}
-#ifdef FIX_BUGS
+		
 		if (nextBlip == NUMRADARBLIPS)
 			return;
-#endif
+			
 		ms_RadarTrace[nextBlip].m_eBlipType = BLIP_COORD;
 		ms_RadarTrace[nextBlip].m_nColor = 0x333333FF;
 		ms_RadarTrace[nextBlip].m_bDim = 1;
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 1393314c..2e112442 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -100,7 +100,8 @@ void FastWeatherCheat();
 void OnlyRenderWheelsCheat();
 void ChittyChittyBangBangCheat();
 void StrongGripCheat();
-void NastyLimbsCheat();
+void SpecialCarCheats();
+void PickUpChicksCheat();
 
 DebugMenuEntry *carCol1;
 DebugMenuEntry *carCol2;
@@ -370,7 +371,8 @@ DebugMenuPopulate(void)
 		DebugMenuAddCmd("Cheats", "Only render wheels", OnlyRenderWheelsCheat);
 		DebugMenuAddCmd("Cheats", "Chitty chitty bang bang", ChittyChittyBangBangCheat);
 		DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat);
-		DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat);
+		DebugMenuAddCmd("Cheats", "Special car", SpecialCarCheats);
+		DebugMenuAddCmd("Cheats", "Pickup chicks", PickUpChicksCheat);
 
 		static int spawnCarId = MI_LANDSTAL;
 		e = DebugMenuAddVar("Spawn", "Spawn Car ID", &spawnCarId, nil, 1, MI_LANDSTAL, MI_VICECHEE, carnames);
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index a8057d26..58aba733 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -257,6 +257,9 @@ enum
 	MI_VICE8,
 	MI_WFYG2 = 106,	// last regular ped
 	MI_SPECIAL01 = 109,
+	MI_SPECIAL02 = 110,
+	MI_SPECIAL03 = 111,
+	MI_SPECIAL04 = 112,
 	MI_SPECIAL21 = 129,
 
 	MI_LAST_PED = MI_SPECIAL21,
diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h
index d9a3f59a..d03ab9bf 100644
--- a/src/modelinfo/VehicleModelInfo.h
+++ b/src/modelinfo/VehicleModelInfo.h
@@ -137,7 +137,7 @@ public:
 	void SetVehicleComponentFlags(RwFrame *frame, uint32 flags);
 	void PreprocessHierarchy(void);
 	void GetWheelPosn(int32 n, CVector &pos);
-	CVector GetFrontSeatPosn(void) { return m_positions[m_vehicleType == VEHICLE_TYPE_BOAT ? BOAT_POS_FRONTSEAT : CAR_POS_FRONTSEAT]; };
+	const CVector &GetFrontSeatPosn(void) { return m_vehicleType == VEHICLE_TYPE_BOAT ? m_positions[BOAT_POS_FRONTSEAT] : m_positions[CAR_POS_FRONTSEAT]; }
 
 	int32 ChooseComponent(void);
 	int32 ChooseSecondComponent(void);
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index f6d54268..c5b19241 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -136,7 +136,6 @@ CVector vecPedBikeKickAnimOffset;
 
 bool CPed::bNastyLimbsCheat;
 bool CPed::bFannyMagnetCheat;
-bool CPed::bPedCheat2;
 bool CPed::bPedCheat3;
 CVector2D CPed::ms_vec2DFleePosition;
 
@@ -14404,7 +14403,7 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh)
 	return true;
 }
 
-extern CVector vecTestTemp(-1.0f, -1.0f, -1.0f);
+CVector vecTestTemp(-1.0f, -1.0f, -1.0f);
 
 // --MIAMI: Done
 void
@@ -21441,4 +21440,4 @@ CPed::SetLook(float direction)
 		SetPedState(PED_LOOK_HEADING);
 		SetLookFlag(direction, false);
 	}
-}
\ No newline at end of file
+}
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index 3ee38df3..1f0e9243 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -1114,7 +1114,6 @@ public:
 
 	static bool bNastyLimbsCheat;
 	static bool bFannyMagnetCheat;
-	static bool bPedCheat2;
 	static bool bPedCheat3;
 	static CVector2D ms_vec2DFleePosition;
 
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index b38f1bd9..b98b8243 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -213,9 +213,7 @@ GenericSave(int file)
 #endif
 	WriteDataToBufferPointer(buf, CGame::currArea);
 	WriteDataToBufferPointer(buf, CVehicle::bAllTaxisHaveNitro);
-	// TODO(Miami): Pad invert Y
-	bool invertY = 0;
-	WriteDataToBufferPointer(buf, invertY);
+	WriteDataToBufferPointer(buf, CPad::bInvertLook4Pad);
 	WriteDataToBufferPointer(buf, CTimeCycle::m_ExtraColour);
 	WriteDataToBufferPointer(buf, CTimeCycle::m_bExtraColourOn);
 	WriteDataToBufferPointer(buf, CTimeCycle::m_ExtraColourInter);
@@ -279,7 +277,8 @@ GenericSave(int file)
 
 		return false;
 	}
-	
+
+	CPad::FixPadsAfterSave();	
 	return true;
 }
 
@@ -352,9 +351,7 @@ GenericLoad()
 #endif
 	ReadDataFromBufferPointer(buf, CGame::currArea);
 	ReadDataFromBufferPointer(buf, CVehicle::bAllTaxisHaveNitro);
-	// TODO(Miami): Pad invert Y
-	bool invertY = 0;
-	ReadDataFromBufferPointer(buf, invertY);
+	ReadDataFromBufferPointer(buf, CPad::bInvertLook4Pad);
 	ReadDataFromBufferPointer(buf, CTimeCycle::m_ExtraColour);
 	ReadDataFromBufferPointer(buf, CTimeCycle::m_bExtraColourOn);
 	ReadDataFromBufferPointer(buf, CTimeCycle::m_ExtraColourInter);
diff --git a/src/skel/events.cpp b/src/skel/events.cpp
index 3e1e95b3..6589ab71 100644
--- a/src/skel/events.cpp
+++ b/src/skel/events.cpp
@@ -9,6 +9,8 @@
 #include "events.h"
 
 
+// --MIAMI: file done
+
 /*
  *****************************************************************************
  */
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 1664ffd0..8c9dd241 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -959,17 +959,24 @@ CBoat::PreRender(void)
 				matrix.Translate(pos);
 				matrix.UpdateRW();
 			}
+			// FIX: Planes can also be controlled with GetCarGunUpDown
+#ifdef FIX_BUGS
+			static float steeringUpDown = 0.0f;
+			steeringUpDown += ((Abs(CPad::GetPad(0)->GetCarGunUpDown()) > 1.0f ? (-CPad::GetPad(0)->GetCarGunUpDown() / 128.0f) : (-CPad::GetPad(0)->GetSteeringUpDown() / 128.0f)) - steeringUpDown) * Min(1.f, CTimer::GetTimeStep() / 5.f);
+#else
+			float steeringUpDown = -CPad::GetPad(0)->GetSteeringUpDown()/128.0f;
+#endif
 			if(m_aBoatNodes[BOAT_REARFLAP_LEFT]){
 				matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_REARFLAP_LEFT]));
 				pos = matrix.GetPosition();
-				matrix.SetRotateX(-CPad::GetPad(0)->GetSteeringUpDown()/128.0f);
+				matrix.SetRotateX(steeringUpDown);
 				matrix.Translate(pos);
 				matrix.UpdateRW();
 			}
 			if(m_aBoatNodes[BOAT_REARFLAP_RIGHT]){
 				matrix.Attach(RwFrameGetMatrix(m_aBoatNodes[BOAT_REARFLAP_RIGHT]));
 				pos = matrix.GetPosition();
-				matrix.SetRotateX(-CPad::GetPad(0)->GetSteeringUpDown()/128.0f);
+				matrix.SetRotateX(steeringUpDown);
 				matrix.Translate(pos);
 				matrix.UpdateRW();
 			}
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 79e27c00..66676869 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -41,6 +41,8 @@ bool CVehicle::bCheat3;
 bool CVehicle::bCheat4;
 bool CVehicle::bCheat5;
 bool CVehicle::bCheat8;
+bool CVehicle::bCheat9;
+bool CVehicle::bCheat10;
 #ifdef ALT_DODO_CHEAT
 bool CVehicle::bAltDodoCheat;
 #endif
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 34106327..b40882d6 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -400,6 +400,8 @@ public:
 	static bool bCheat4;
 	static bool bCheat5;
 	static bool bCheat8;
+	static bool bCheat9;
+	static bool bCheat10;
 #ifdef ALT_DODO_CHEAT
 	static bool bAltDodoCheat;
 #endif
diff --git a/src/weapons/BulletInfo.cpp b/src/weapons/BulletInfo.cpp
index 0efe6688..375a2ca9 100644
--- a/src/weapons/BulletInfo.cpp
+++ b/src/weapons/BulletInfo.cpp
@@ -23,6 +23,9 @@
 #include "WeaponInfo.h"
 #include "World.h"
 #include "SurfaceTable.h"
+#include "Heli.h"
+
+// --MIAMI: file done
 
 #ifdef SQUEEZE_PERFORMANCE
 uint32 bulletInfoInUse;
@@ -32,9 +35,14 @@ uint32 bulletInfoInUse;
 #define NUM_PED_BLOOD_PARTICLES (8)
 #define BLOOD_PARTICLE_OFFSET (CVector(0.0f, 0.0f, 0.0f))
 #define NUM_VEHICLE_SPARKS (16)
+#define NUM_TYRE_POP_SMOKES (4)
 #define NUM_OTHER_SPARKS (8)
 #define BULLET_HIT_FORCE (7.5f)
-#define MAP_BORDER (1960.0f)
+
+#define BULLET_BOUNDARY_MIN_X -2400.0f
+#define BULLET_BOUNDARY_MAX_X 1600.0f
+#define BULLET_BOUNDARY_MIN_Y -2000.0f
+#define BULLET_BOUNDARY_MAX_Y 2000.0f
 
 CBulletInfo gaBulletInfo[CBulletInfo::NUM_BULLETS];
 bool bPlayerSniperBullet;
@@ -106,14 +114,18 @@ void CBulletInfo::Update(void)
 		}
 		CVector vecOldPos = pBullet->m_vecPosition;
 		CVector vecNewPos = pBullet->m_vecPosition + pBullet->m_vecSpeed * CTimer::GetTimeStep() * 0.5f;
-		CWorld::bIncludeCarTyres = true;
+
+		if ( vecNewPos.x <= BULLET_BOUNDARY_MIN_X || vecNewPos.x >= BULLET_BOUNDARY_MAX_X || vecNewPos.y <= BULLET_BOUNDARY_MIN_Y || vecNewPos.y >= BULLET_BOUNDARY_MAX_Y ) {
+			pBullet->m_bInUse = false;
+			continue;
+		}
 		CWorld::bIncludeDeadPeds = true;
+		CWorld::bIncludeBikers = true;
+		CWorld::bIncludeCarTyres = true;
 		CWorld::pIgnoreEntity = pBullet->m_pSource;
 		CColPoint point;
 		CEntity* pHitEntity;
 		if (CWorld::ProcessLineOfSight(vecOldPos, vecNewPos, point, pHitEntity, true, true, true, true, true, false, false, true)) {
-			if (pBullet->m_pSource && (pHitEntity->IsPed() || pHitEntity->IsVehicle()))
-				CStats::BulletsThatHit++;
 
 			CWeapon::CheckForShootingVehicleOccupant(&pHitEntity, &point, pBullet->m_eWeaponType, vecOldPos, vecNewPos);
 			if (pHitEntity->IsPed()) {
@@ -128,7 +140,7 @@ void CBulletInfo::Update(void)
 					CEventList::RegisterEvent(pPed->m_nPedType == PEDTYPE_COP ? EVENT_SHOOT_COP : EVENT_SHOOT_PED, EVENT_ENTITY_PED, pPed, (CPed*)pBullet->m_pSource, 1000);
 					pBullet->m_bInUse = false;
 #ifdef SQUEEZE_PERFORMANCE
-						bulletInfoInUse--;
+					bulletInfoInUse--;
 #endif
 					vecNewPos = point.point;
 				}
@@ -159,13 +171,24 @@ void CBulletInfo::Update(void)
 				}
 			}
 			else if (pHitEntity->IsVehicle()) {
-				CVehicle* pVehicle = (CVehicle*)pHitEntity;
-				pVehicle->InflictDamage(pBullet->m_pSource, pBullet->m_eWeaponType, pBullet->m_nDamage);
-				if (pBullet->m_eWeaponType == WEAPONTYPE_FLAMETHROWER) // huh?
-					gFireManager.StartFire(pVehicle, pBullet->m_pSource, 0.8f, true);
-				else {
-					for (int j = 0; j < NUM_VEHICLE_SPARKS; j++)
-						CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal / 20);
+				CEntity *source = pBullet->m_pSource;
+				if ( !source || !source->IsPed() || ((CPed*)source)->m_attachedTo != pHitEntity) {
+					if ( point.pieceB >= CAR_PIECE_WHEEL_LF && point.pieceB <= CAR_PIECE_WHEEL_RR ) {
+						((CVehicle*)pHitEntity)->BurstTyre(point.pieceB, true);
+						for (int j=0; j<NUM_TYRE_POP_SMOKES; j++) {
+							CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, point.point, point.normal / 20);
+						}
+					} else {
+						// CVector sth(0.0f, 0.0f, 0.0f); // unused
+						((CVehicle*)pHitEntity)->InflictDamage(source, pBullet->m_eWeaponType, pBullet->m_nDamage);
+						if ( pBullet->m_eWeaponType == WEAPONTYPE_FLAMETHROWER ) {
+							gFireManager.StartFire(pHitEntity, pBullet->m_pSource, 0.8f, 1);
+						} else {
+							for (int j=0; j<NUM_VEHICLE_SPARKS; j++) {
+								CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal / 20);
+							}
+						}
+					}
 				}
 #ifdef FIX_BUGS
 				pBullet->m_bInUse = false;
@@ -174,19 +197,28 @@ void CBulletInfo::Update(void)
 #endif
 				vecNewPos = point.point;
 #endif
-			}
-			else {
+			} else {
 				for (int j = 0; j < NUM_OTHER_SPARKS; j++)
 					CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal / 20);
-				if (pHitEntity->IsObject()) {
-					CObject* pObject = (CObject*)pHitEntity;
-					if (!pObject->bInfiniteMass) {
-						if (pObject->IsStatic() && pObject->m_fUprootLimit <= 0.0f) {
-							pObject->bIsStatic = false;
-							pObject->AddToMovingList();
+				CEntity *source = pBullet->m_pSource;
+				if ( !source || !source->IsPed() || ((CPed*)source)->m_attachedTo != pHitEntity) {
+					if (pHitEntity->IsObject()) {
+						CObject *pHitObject = (CObject*)pHitEntity;
+						if ( !pHitObject->bInfiniteMass && pHitObject->m_fCollisionDamageMultiplier < 99.9f) {
+							bool notStatic = !pHitObject->IsStatic();
+							if (notStatic && pHitObject->m_fUprootLimit <= 0.0f) {
+								pHitObject->bIsStatic = false;
+								pHitObject->AddToMovingList();
+							}
+
+							notStatic = !pHitObject->IsStatic();
+							if (!notStatic) {
+								CVector moveForce = point.normal * -BULLET_HIT_FORCE;
+								pHitObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z);
+							}
+						} else if (pHitObject->m_nCollisionDamageEffect >= DAMAGE_EFFECT_SMASH_COMPLETELY) {
+							pHitObject->ObjectDamage(50.f);
 						}
-						if (!pObject->IsStatic())
-							pObject->ApplyMoveForce(-BULLET_HIT_FORCE * point.normal);
 					}
 				}
 #ifdef FIX_BUGS
@@ -200,35 +232,52 @@ void CBulletInfo::Update(void)
 			if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || pBullet->m_eWeaponType == WEAPONTYPE_LASERSCOPE) {
 				cAudioScriptObject* pAudio;
 				switch (pHitEntity->GetType()) {
-				case ENTITY_TYPE_BUILDING:
-					pAudio = new cAudioScriptObject();
-					pAudio->Posn = pHitEntity->GetPosition();
-					pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_1;
-					pAudio->AudioEntity = AEHANDLE_NONE;
-					DMAudio.CreateOneShotScriptObject(pAudio);
-					break;
-				case ENTITY_TYPE_OBJECT:
-					pAudio = new cAudioScriptObject();
-					pAudio->Posn = pHitEntity->GetPosition();
-					pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_2;
-					pAudio->AudioEntity = AEHANDLE_NONE;
-					DMAudio.CreateOneShotScriptObject(pAudio);
-					break;
-				case ENTITY_TYPE_DUMMY:
-					pAudio = new cAudioScriptObject();
-					pAudio->Posn = pHitEntity->GetPosition();
-					pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_3;
-					pAudio->AudioEntity = AEHANDLE_NONE;
-					DMAudio.CreateOneShotScriptObject(pAudio);
-					break;
-				case ENTITY_TYPE_PED:
-					DMAudio.PlayOneShot(((CPed*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
-					((CPed*)pHitEntity)->Say(SOUND_PED_BULLET_HIT);
-					break;
-				case ENTITY_TYPE_VEHICLE:
-					DMAudio.PlayOneShot(((CVehicle*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
-					break;
-				default: break;
+					case ENTITY_TYPE_BUILDING:
+						if (!DMAudio.IsAudioInitialised())
+							break;
+
+						pAudio = new cAudioScriptObject();
+						if (pAudio)
+							pAudio->Reset();
+						pAudio->Posn = pHitEntity->GetPosition();
+						pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_1;
+						pAudio->AudioEntity = AEHANDLE_NONE;
+						DMAudio.CreateOneShotScriptObject(pAudio);
+						break;
+					case ENTITY_TYPE_OBJECT:
+						if (!DMAudio.IsAudioInitialised())
+							break;
+
+						pAudio = new cAudioScriptObject();
+						if (pAudio)
+							pAudio->Reset();
+						pAudio->Posn = pHitEntity->GetPosition();
+						pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_2;
+						pAudio->AudioEntity = AEHANDLE_NONE;
+						DMAudio.CreateOneShotScriptObject(pAudio);
+						break;
+					case ENTITY_TYPE_DUMMY:
+						if (!DMAudio.IsAudioInitialised())
+							break;
+
+						pAudio = new cAudioScriptObject();
+						if (pAudio)
+							pAudio->Reset();
+						pAudio->Posn = pHitEntity->GetPosition();
+						pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_3;
+						pAudio->AudioEntity = AEHANDLE_NONE;
+						DMAudio.CreateOneShotScriptObject(pAudio);
+						break;
+					case ENTITY_TYPE_PED:
+						++CStats::BulletsThatHit;
+						DMAudio.PlayOneShot(((CPed*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+						((CPed*)pHitEntity)->Say(SOUND_PED_BULLET_HIT);
+						break;
+					case ENTITY_TYPE_VEHICLE:
+						++CStats::BulletsThatHit;
+						DMAudio.PlayOneShot(((CVehicle*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+						break;
+						default: break;
 				}
 			}
 			CGlass::WasGlassHitByBullet(pHitEntity, point.point);
@@ -237,19 +286,14 @@ void CBulletInfo::Update(void)
 		CWorld::pIgnoreEntity = nil;
 		CWorld::bIncludeDeadPeds = false;
 		CWorld::bIncludeCarTyres = false;
+		CWorld::bIncludeBikers = false;
 		if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || pBullet->m_eWeaponType == WEAPONTYPE_LASERSCOPE) {
 			bPlayerSniperBullet = true;
 			PlayerSniperBulletStart = pBullet->m_vecPosition;
 			PlayerSniperBulletEnd = vecNewPos;
 		}
 		pBullet->m_vecPosition = vecNewPos;
-		if (pBullet->m_vecPosition.x < -MAP_BORDER || pBullet->m_vecPosition.x > MAP_BORDER ||
-			pBullet->m_vecPosition.y < -MAP_BORDER || pBullet->m_vecPosition.y > MAP_BORDER) {
-			pBullet->m_bInUse = false;
-#ifdef SQUEEZE_PERFORMANCE
-			bulletInfoInUse--;
-#endif
-		}
+		CHeli::TestSniperCollision(&PlayerSniperBulletStart, &PlayerSniperBulletEnd);
 	}
 }
 
diff --git a/src/weapons/ProjectileInfo.cpp b/src/weapons/ProjectileInfo.cpp
index 4150852a..71cd9cfb 100644
--- a/src/weapons/ProjectileInfo.cpp
+++ b/src/weapons/ProjectileInfo.cpp
@@ -17,9 +17,16 @@
 uint32 projectileInUse;
 #endif
 
+// --MIAMI: file done except TODOs
+
 CProjectileInfo gaProjectileInfo[NUM_PROJECTILES];
 CProjectile *CProjectileInfo::ms_apProjectile[NUM_PROJECTILES];
 
+#define PROJECTILE_BOUNDARY_MIN_X -2390.0f
+#define PROJECTILE_BOUNDARY_MAX_X 1590.0f
+#define PROJECTILE_BOUNDARY_MIN_Y -1990.0f
+#define PROJECTILE_BOUNDARY_MAX_Y 1990.0f
+
 void
 CProjectileInfo::Initialise()
 {
@@ -53,7 +60,6 @@ CProjectileInfo::GetProjectileInfo(int32 id)
 	return &gaProjectileInfo[id];
 }
 
-// --MIAMI: Mostly done
 bool
 CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, float speed)
 {
@@ -67,70 +73,87 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos,
 
 	switch (weapon)
 	{
-	case WEAPONTYPE_ROCKET:
-	{
-		float vy = 0.35f;
-		time = CTimer::GetTimeInMilliseconds() + 2000;
-		if (entity->GetModelIndex() == MI_SPARROW || entity->GetModelIndex() == MI_HUNTER || entity->GetModelIndex() == MI_SENTINEL) {
-			matrix = ped->GetMatrix();
-			matrix.GetPosition() = pos;
-			CVector vecSpeed = ((CPhysical*)entity)->m_vecMoveSpeed;
-			vy += Max(0.0f, DotProduct(vecSpeed, entity->GetForward())) + Max(0.0f, DotProduct(vecSpeed, entity->GetUp()));
-		} else {
-			if (ped->IsPlayer()) {
-				matrix.GetForward() = TheCamera.Cams[TheCamera.ActiveCam].Front;
-				matrix.GetUp() = TheCamera.Cams[TheCamera.ActiveCam].Up;
-				matrix.GetRight() = CrossProduct(TheCamera.Cams[TheCamera.ActiveCam].Up, TheCamera.Cams[TheCamera.ActiveCam].Front);
-				matrix.GetPosition() = pos;
-			} else if (ped->m_pSeekTarget != nil) {
-				float ry = CGeneral::GetRadianAngleBetweenPoints(1.0f, ped->m_pSeekTarget->GetPosition().z, 1.0f, pos.z);
-				float rz = Atan2(-ped->GetForward().x, ped->GetForward().y);
-				vy = 0.35f * speed + 0.15f;
-				matrix.SetTranslate(0.0f, 1.0f, 1.0f);
-				matrix.Rotate(0.0f, ry, rz);
-				matrix.GetPosition() += pos;
-			} else {
+		case WEAPONTYPE_ROCKET:
+		{
+			float vy = 0.35f;
+			time = CTimer::GetTimeInMilliseconds() + 2000;
+			if (entity->GetModelIndex() == MI_SPARROW || entity->GetModelIndex() == MI_HUNTER || entity->GetModelIndex() == MI_SENTINEL) {
 				matrix = ped->GetMatrix();
+				matrix.GetPosition() = pos;
+				CVector vecSpeed = ((CPhysical*)entity)->m_vecMoveSpeed;
+				vy += Max(0.0f, DotProduct(vecSpeed, entity->GetForward())) + Max(0.0f, DotProduct(vecSpeed, entity->GetUp()));
+			} else {
+				if (ped->IsPlayer()) {
+					matrix.GetForward() = TheCamera.Cams[TheCamera.ActiveCam].Front;
+					matrix.GetUp() = TheCamera.Cams[TheCamera.ActiveCam].Up;
+					matrix.GetRight() = CrossProduct(TheCamera.Cams[TheCamera.ActiveCam].Up, TheCamera.Cams[TheCamera.ActiveCam].Front);
+					matrix.GetPosition() = pos;
+				} else if (ped->m_pSeekTarget != nil) {
+					float ry = CGeneral::GetRadianAngleBetweenPoints(1.0f, ped->m_pSeekTarget->GetPosition().z, 1.0f, pos.z);
+					float rz = Atan2(-ped->GetForward().x, ped->GetForward().y);
+					vy = 0.35f * speed + 0.15f;
+					matrix.SetTranslate(0.0f, 1.0f, 1.0f);
+					matrix.Rotate(0.0f, ry, rz);
+					matrix.GetPosition() += pos;
+				} else {
+					matrix = ped->GetMatrix();
+				}
 			}
+			velocity = Multiply3x3(matrix, CVector(0.0f, vy, 0.0f));
+			gravity = false;
+			break;
 		}
-		velocity = Multiply3x3(matrix, CVector(0.0f, vy, 0.0f));
-		gravity = false;
-		break;
-	}
-	case WEAPONTYPE_MOLOTOV:
-	{
-		time = CTimer::GetTimeInMilliseconds() + 2000;
-		float scale = 0.22f * speed + 0.15f;
-		if (scale < 0.2f)
-			scale = 0.2f;
-		float angle = Atan2(-ped->GetForward().x, ped->GetForward().y);
-		matrix.SetTranslate(0.0f, 0.0f, 0.0f);
-		matrix.RotateZ(angle);
-		matrix.GetPosition() += pos;
-		velocity.x = -1.0f * scale * Sin(angle);
-		velocity.y = scale * Cos(angle);
-		velocity.z = (0.2f * speed + 0.4f) * scale;
-		break;
-	}
-	case WEAPONTYPE_GRENADE:
-	case WEAPONTYPE_DETONATOR_GRENADE:
-	{
-		time = CTimer::GetTimeInMilliseconds() + 2000;
-		float scale = 0.0f;
-		if (speed != 0.0f)
-			scale = 0.22f * speed + 0.15f;
-		float angle = Atan2(-ped->GetForward().x, ped->GetForward().y);
-		matrix.SetTranslate(0.0f, 0.0f, 0.0f);
-		matrix.RotateZ(angle);
-		matrix.GetPosition() += pos;
-		SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5;
-		velocity.x = -1.0f * scale * Sin(angle);
-		velocity.y = scale * Cos(angle);
-		velocity.z = (0.4f * speed + 0.4f) * scale;
-		elasticity = 0.5f;
-		break;
-	}
-	default:
+		case WEAPONTYPE_MOLOTOV:
+		{
+			time = CTimer::GetTimeInMilliseconds() + 2000;
+			float scale = 0.22f * speed + 0.15f;
+			if (scale < 0.2f)
+				scale = 0.2f;
+			float angle = Atan2(-ped->GetForward().x, ped->GetForward().y);
+			matrix.SetTranslate(0.0f, 0.0f, 0.0f);
+			matrix.RotateZ(angle);
+			matrix.GetPosition() += pos;
+			velocity.x = -1.0f * scale * Sin(angle);
+			velocity.y = scale * Cos(angle);
+			velocity.z = (0.2f * speed + 0.4f) * scale;
+			break;
+		}
+		case WEAPONTYPE_TEARGAS:
+		{
+			time = CTimer::GetTimeInMilliseconds() + 20000;
+			float scale = 0.0f;
+			if (speed != 0.0f)
+				scale = 0.22f * speed + 0.15f;
+			float angle = Atan2(-ped->GetForward().x, ped->GetForward().y);
+			matrix.SetTranslate(0.0f, 0.0f, 0.0f);
+			matrix.RotateZ(angle);
+			matrix.GetPosition() += pos;
+			SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5;
+			velocity.x = -1.0f * scale * Sin(angle);
+			velocity.y = scale * Cos(angle);
+			velocity.z = (0.4f * speed + 0.4f) * scale;
+			elasticity = 0.5f;
+			break;
+		}
+		case WEAPONTYPE_GRENADE:
+		case WEAPONTYPE_DETONATOR_GRENADE:
+		{
+			time = CTimer::GetTimeInMilliseconds() + 2000;
+			float scale = 0.0f;
+			if (speed != 0.0f)
+				scale = 0.22f * speed + 0.15f;
+			float angle = Atan2(-ped->GetForward().x, ped->GetForward().y);
+			matrix.SetTranslate(0.0f, 0.0f, 0.0f);
+			matrix.RotateZ(angle);
+			matrix.GetPosition() += pos;
+			SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5;
+			velocity.x = -1.0f * scale * Sin(angle);
+			velocity.y = scale * Cos(angle);
+			velocity.z = (0.4f * speed + 0.4f) * scale;
+			elasticity = 0.5f;
+			break;
+		}
+		default:
 		Error("Undefined projectile type, AddProjectile, ProjectileInfo.cpp");
 		break;
 	}
@@ -143,19 +166,20 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos,
 
 	switch (weapon)
 	{
-	case WEAPONTYPE_ROCKET:
+		case WEAPONTYPE_ROCKET:
 		ms_apProjectile[i] = new CProjectile(MI_MISSILE);
 		break;
-	case WEAPONTYPE_FLAMETHROWER:
+		case WEAPONTYPE_TEARGAS:
+		ms_apProjectile[i] = new CProjectile(MI_TEARGAS);
 		break;
-	case WEAPONTYPE_MOLOTOV:
+		case WEAPONTYPE_MOLOTOV:
 		ms_apProjectile[i] = new CProjectile(MI_MOLOTOV);
 		break;
-	case WEAPONTYPE_GRENADE:
-	case WEAPONTYPE_DETONATOR_GRENADE:
+		case WEAPONTYPE_GRENADE:
+		case WEAPONTYPE_DETONATOR_GRENADE:
 		ms_apProjectile[i] = new CProjectile(MI_GRENADE);
 		break;
-	default: break;
+		default: break;
 	}
 
 	if (ms_apProjectile[i] == nil)
@@ -189,7 +213,18 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos,
 void
 CProjectileInfo::RemoveProjectile(CProjectileInfo *info, CProjectile *projectile)
 {
-	RemoveNotAdd(info->m_pSource, info->m_eWeaponType, projectile->GetPosition());
+	// TODO(Miami): New parameter: 1
+	switch (info->m_eWeaponType) {
+		case WEAPONTYPE_GRENADE:
+			CExplosion::AddExplosion(nil, info->m_pSource, EXPLOSION_GRENADE, projectile->GetPosition(), 0);
+			break;
+		case WEAPONTYPE_MOLOTOV:
+			CExplosion::AddExplosion(nil, info->m_pSource, EXPLOSION_MOLOTOV, projectile->GetPosition(), 0);
+			break;
+		case WEAPONTYPE_ROCKET:
+			CExplosion::AddExplosion(nil, info->m_pSource->IsVehicle() ? ((CVehicle*)info->m_pSource)->pDriver : info->m_pSource, EXPLOSION_ROCKET, projectile->GetPosition(), 0);
+			break;
+	}
 #ifdef SQUEEZE_PERFORMANCE
 	projectileInUse--;
 #endif
@@ -202,18 +237,17 @@ CProjectileInfo::RemoveProjectile(CProjectileInfo *info, CProjectile *projectile
 void
 CProjectileInfo::RemoveNotAdd(CEntity *entity, eWeaponType weaponType, CVector pos)
 {
-	switch (weaponType)
-	{
-	case WEAPONTYPE_GRENADE:
-		CExplosion::AddExplosion(nil, entity, EXPLOSION_GRENADE, pos, 0);
-		break;
-	case WEAPONTYPE_MOLOTOV:
-		CExplosion::AddExplosion(nil, entity, EXPLOSION_MOLOTOV, pos, 0);
-		break;
-	case WEAPONTYPE_ROCKET:
-		CExplosion::AddExplosion(nil, entity, EXPLOSION_ROCKET, pos, 0);
-		break;
-	default: break;
+	// TODO(Miami): New parameter: 1
+	switch (weaponType) {
+		case WEAPONTYPE_GRENADE:
+			CExplosion::AddExplosion(nil, entity, EXPLOSION_GRENADE, pos, 0);
+			break;
+		case WEAPONTYPE_MOLOTOV:
+			CExplosion::AddExplosion(nil, entity, EXPLOSION_MOLOTOV, pos, 0);
+			break;
+		case WEAPONTYPE_ROCKET:
+			CExplosion::AddExplosion(nil, entity, EXPLOSION_ROCKET, pos, 0);
+			break;
 	}
 }
 
@@ -225,6 +259,8 @@ CProjectileInfo::Update()
 		return;
 #endif
 
+	int tearGasOffset = -0.0f; // unused
+	
 	for (int i = 0; i < ARRAY_SIZE(gaProjectileInfo); i++) {
 		if (!gaProjectileInfo[i].m_bInUse) continue;
 
@@ -240,21 +276,48 @@ CProjectileInfo::Update()
 			gaProjectileInfo[i].m_bInUse = false;
 			continue;
 		}
+		if ( (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_TEARGAS) && ms_apProjectile[i]->m_fElasticity > 0.1f ) {
+			if ( Abs(ms_apProjectile[i]->m_vecMoveSpeed.x) < 0.05f && Abs(ms_apProjectile[i]->m_vecMoveSpeed.y) < 0.05f && Abs(ms_apProjectile[i]->m_vecMoveSpeed.z) < 0.05f ) {
+				ms_apProjectile[i]->m_fElasticity = 0.03f;
+			}
+		}
+		const CVector &projectilePos = ms_apProjectile[i]->GetPosition();
+		CVector nextPos = CTimer::GetTimeStep() * ms_apProjectile[i]->m_vecMoveSpeed + projectilePos;
 
-		if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) {
-			CParticle::AddParticle(PARTICLE_SMOKE, ms_apProjectile[i]->GetPosition(), CVector(0.0f, 0.0f, 0.0f));
+		if ( nextPos.x <= PROJECTILE_BOUNDARY_MIN_X || nextPos.x >= PROJECTILE_BOUNDARY_MAX_X || nextPos.y <= PROJECTILE_BOUNDARY_MIN_Y || nextPos.y >= PROJECTILE_BOUNDARY_MAX_Y ) {
+			// Not RemoveProjectile, because we don't want no explosion
+			gaProjectileInfo[i].m_bInUse = false;
+			CWorld::Remove(ms_apProjectile[i]);
+			delete ms_apProjectile[i];
+        	continue;
+		}
+		if ( gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_TEARGAS && CTimer::GetTimeInMilliseconds() > gaProjectileInfo[i].m_nExplosionTime - 19500 ) {
+			CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(0.2f, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0);
+			CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(-0.2f, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0);
+			CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(tearGasOffset, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0);
+
+			// TODO(Miami): SetPedsChoking
+			/*if ( CTimer::GetTimeInMilliseconds() & 0x200 )
+				CWorld::SetPedsChoking(projectilePos.x, projectilePos.y, projectilePos.z, 6.0f, gaProjectileInfo[i].m_pSource);
+			*/
 		}
 
-		if (CTimer::GetTimeInMilliseconds() <= gaProjectileInfo[i].m_nExplosionTime) {
+		if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) {
+			CParticle::AddParticlesAlongLine(PARTICLE_ROCKET_SMOKE, gaProjectileInfo[i].m_vecPos, projectilePos, CVector(0.0f, 0.0f, 0.0f), 0.7f, 0, 0, 0, 3000);
+		}
+
+		if (CTimer::GetTimeInMilliseconds() <= gaProjectileInfo[i].m_nExplosionTime || gaProjectileInfo[i].m_nExplosionTime == 0) {
 			if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) {
 				CVector pos = ms_apProjectile[i]->GetPosition();
 				CWorld::pIgnoreEntity = ms_apProjectile[i];
 				if (ms_apProjectile[i]->bHasCollided
 					|| !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false)
-					|| gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET && (CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos))) {
+					|| CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos)) {
 					RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]);
 				}
 				CWorld::pIgnoreEntity = nil;
+				ms_apProjectile[i]->m_vecMoveSpeed *= 1.07f;
+
 			} else if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_MOLOTOV) {
 				CVector pos = ms_apProjectile[i]->GetPosition();
 				CWorld::pIgnoreEntity = ms_apProjectile[i];
@@ -263,8 +326,7 @@ CProjectileInfo::Update()
 					|| ((gaProjectileInfo[i].m_vecPos - gaProjectileInfo[i].m_pSource->GetPosition()).MagnitudeSqr() >= 2.0f))
 				{
 					if (ms_apProjectile[i]->bHasCollided
-						|| !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false)
-						|| gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET && (CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos))) {
+						|| !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false)) {
 						RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]);
 					}
 				}
@@ -315,13 +377,12 @@ CProjectileInfo::IsProjectileInRange(float x1, float x2, float y1, float y2, flo
 	return result;
 }
 
-// --MIAMI: Done
 void
 CProjectileInfo::RemoveDetonatorProjectiles()
 {
 	for (int i = 0; i < ARRAY_SIZE(ms_apProjectile); i++) {
 		if (gaProjectileInfo[i].m_bInUse && gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE) {
-			CExplosion::AddExplosion(nil, gaProjectileInfo[i].m_pSource, EXPLOSION_GRENADE, gaProjectileInfo[i].m_vecPos, 0); // TODO(Miami): New parameter (1)
+			CExplosion::AddExplosion(nil, gaProjectileInfo[i].m_pSource, EXPLOSION_GRENADE, gaProjectileInfo[i].m_vecPos, 0); // TODO(Miami): New parameter: 1
 			gaProjectileInfo[i].m_bInUse = false;
 			CWorld::Remove(ms_apProjectile[i]);
 			delete ms_apProjectile[i];