From 2100bdd5295d63359bb901a765ec7fdde0065ba2 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 7 Apr 2020 01:19:24 +0200
Subject: [PATCH 1/8] implemented CRubbish

---
 README.md              |   1 -
 src/render/Rubbish.cpp | 422 ++++++++++++++++++++++++++++++++++++++++-
 src/render/Rubbish.h   |  39 +++-
 3 files changed, 454 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index e1b1b340..5d81e0b2 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,6 @@ CPools - save/loading
 CRecordDataForChase
 CRecordDataForGame
 CRoadBlocks
-CRubbish
 CSceneEdit
 CSkidmarks
 CSpecialFX
diff --git a/src/render/Rubbish.cpp b/src/render/Rubbish.cpp
index a52e59a0..65d8b2dd 100644
--- a/src/render/Rubbish.cpp
+++ b/src/render/Rubbish.cpp
@@ -1,10 +1,420 @@
 #include "common.h"
+#include "main.h"
 #include "patcher.h"
+#include "General.h"
+#include "Timer.h"
+#include "Weather.h"
+#include "Camera.h"
+#include "World.h"
+#include "Vehicle.h"
+#include "ZoneCull.h"
+#include "TxdStore.h"
+#include "RenderBuffer.h"
 #include "Rubbish.h"
 
-WRAPPER void CRubbish::Render(void) { EAXJMP(0x512190); }
-WRAPPER void CRubbish::StirUp(CVehicle *veh) { EAXJMP(0x512690); }
-WRAPPER void CRubbish::Update(void) { EAXJMP(0x511B90); }
-WRAPPER void CRubbish::SetVisibility(bool) { EAXJMP(0x512AA0); }
-WRAPPER void CRubbish::Init(void) { EAXJMP(0x511940); }
-WRAPPER void CRubbish::Shutdown(void) { EAXJMP(0x511B50); }
+#define RUBBISH_MAX_DIST (18.0f)
+#define RUBBISH_FADE_DIST (16.5f)
+
+RwTexture *gpRubbishTexture[4];
+RwImVertexIndex RubbishIndexList[6];
+RwImVertexIndex RubbishIndexList2[6];	// unused
+RwIm3DVertex RubbishVertices[4];
+bool CRubbish::bRubbishInvisible;
+int CRubbish::RubbishVisibility;
+COneSheet CRubbish::aSheets[NUM_RUBBISH_SHEETS];
+COneSheet CRubbish::StartEmptyList;
+COneSheet CRubbish::EndEmptyList;
+COneSheet CRubbish::StartStaticsList;
+COneSheet CRubbish::EndStaticsList;
+COneSheet CRubbish::StartMoversList;
+COneSheet CRubbish::EndMoversList;
+
+
+void
+COneSheet::AddToList(COneSheet *list)
+{
+	this->m_next = list->m_next;
+	this->m_prev = list;
+	list->m_next = this;
+	this->m_next->m_prev = this;
+}
+
+void
+COneSheet::RemoveFromList(void)
+{
+	m_next->m_prev = m_prev;
+	m_prev->m_next = m_next;
+}
+
+
+void
+CRubbish::Render(void)
+{
+	int type;
+
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
+
+	for(type = 0; type < 4; type++){
+		RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRubbishTexture[type]));
+
+		TempBufferIndicesStored = 0;
+		TempBufferVerticesStored = 0;
+
+		COneSheet *sheet;
+		for(sheet = &aSheets[type*NUM_RUBBISH_SHEETS / 4];
+		    sheet < &aSheets[(type+1)*NUM_RUBBISH_SHEETS / 4];
+		    sheet++){
+			if(sheet->m_state == 0)
+				continue;
+
+			uint32 alpha = 128;
+			CVector pos;
+			if(sheet->m_state == 1){
+				pos = sheet->m_basePos;
+				if(!sheet->m_isVisible)
+					alpha = 0;
+			}else{
+				pos = sheet->m_animatedPos;
+				// Not fully visible during animation, calculate current alpha
+				if(!sheet->m_isVisible || !sheet->m_targetIsVisible){
+					float t = (float)(CTimer::GetTimeInMilliseconds() - sheet->m_moveStart)/sheet->m_moveDuration;
+					float f1 = sheet->m_isVisible ? 1.0f-t : 0.0f;
+					float f2 = sheet->m_targetIsVisible ? t : 0.0f;
+					alpha = 128 * (f1+f2);
+				}
+			}
+
+			float camDist = (pos - TheCamera.GetPosition()).Magnitude2D();
+			if(camDist < RUBBISH_MAX_DIST){
+				if(camDist >= RUBBISH_FADE_DIST)
+					alpha -= alpha*(camDist-RUBBISH_FADE_DIST)/(RUBBISH_MAX_DIST-RUBBISH_FADE_DIST);
+				alpha = (RubbishVisibility*alpha)/256;
+
+				float vx = Sin(sheet->m_angle) * 0.4f;
+				float vy = Cos(sheet->m_angle) * 0.4f;
+
+				int v = TempBufferVerticesStored;
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], pos.x + vx, pos.y + vy, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], 255, 255, 255, alpha);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], pos.x - vy, pos.y + vx, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], 255, 255, 255, alpha);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], pos.x + vy, pos.y - vx, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], 255, 255, 255, alpha);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], pos.x - vx, pos.y - vy, pos.z);
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], 255, 255, 255, alpha);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], 0.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], 0.0f);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], 1.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], 0.0f);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], 0.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], 1.0f);
+				RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], 1.0f);
+				RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], 1.0f);
+
+				int i = TempBufferIndicesStored;
+				TempBufferRenderIndexList[i+0] = RubbishIndexList[0] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+1] = RubbishIndexList[1] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+2] = RubbishIndexList[2] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+3] = RubbishIndexList[3] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+4] = RubbishIndexList[4] + TempBufferVerticesStored;
+				TempBufferRenderIndexList[i+5] = RubbishIndexList[5] + TempBufferVerticesStored;
+				TempBufferVerticesStored += 4;
+				TempBufferIndicesStored += 6;
+			}
+		}
+
+		if(TempBufferIndicesStored != 0){
+			LittleTest();
+			if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+				RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+				RwIm3DEnd();
+			}
+		}
+	}
+
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+}
+
+void
+CRubbish::StirUp(CVehicle *veh)
+{
+	if((CTimer::GetFrameCounter() ^ (veh->m_randomSeed&3)) == 0)
+		return;
+
+	if(Abs(veh->GetPosition().x - TheCamera.GetPosition().x) < 20.0f &&
+	   Abs(veh->GetPosition().y - TheCamera.GetPosition().y) < 20.0f)
+		if(Abs(veh->GetMoveSpeed().x) > 0.05f || Abs(veh->GetMoveSpeed().y) > 0.05f){
+			float speed = veh->GetMoveSpeed().Magnitude2D();
+			if(speed > 0.05f){
+				bool movingForward = DotProduct2D(veh->GetMoveSpeed(), veh->GetForward()) > 0.0f;
+				COneSheet *sheet = StartStaticsList.m_next;
+				CVector2D size = veh->GetColModel()->boundingBox.max;
+
+				// Check all static sheets
+				while(sheet != &EndStaticsList){
+					COneSheet *next = sheet->m_next;
+					CVector2D carToSheet = sheet->m_basePos - veh->GetPosition();
+					float distFwd = DotProduct2D(carToSheet, veh->GetForward());
+
+					// sheet has to be a bit behind car
+					if(movingForward && distFwd < -0.5f*size.y && distFwd > -1.5f*size.y ||
+					   !movingForward && distFwd > 0.5f*size.y && distFwd < 1.5f*size.y){
+						float distSide = Abs(DotProduct2D(carToSheet, veh->GetRight()));
+						if(distSide < 1.5*size.x){
+							// Check with higher speed for sheet directly behind car
+							float speedToCheck = distSide < size.x ? speed : speed*0.5f;
+							if(speedToCheck > 0.05f){
+								sheet->m_state = 2;
+								if(speedToCheck > 0.15f)
+									sheet->m_animationType = 2;
+								else
+									sheet->m_animationType = 1;
+								sheet->m_moveDuration = 2000;
+								sheet->m_xDist = veh->GetMoveSpeed().x;
+								sheet->m_yDist = veh->GetMoveSpeed().y;
+								float dist = Sqrt(SQR(sheet->m_xDist)+SQR(sheet->m_yDist));
+								sheet->m_xDist *= 25.0f*speed/dist;
+								sheet->m_yDist *= 25.0f*speed/dist;
+								sheet->m_animHeight = 3.0f*speed;
+								sheet->m_moveStart = CTimer::GetTimeInMilliseconds();
+								float tx = sheet->m_basePos.x + sheet->m_xDist;
+								float ty = sheet->m_basePos.y + sheet->m_yDist;
+								float tz = sheet->m_basePos.z + 3.0f;
+								sheet->m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, nil) + 0.1f;
+								sheet->RemoveFromList();
+								sheet->AddToList(&StartMoversList);
+							}
+						}
+					}
+
+					sheet = next;
+				}
+			}
+		}
+}
+
+static float aAnimations[3][34] = {
+	{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+	  0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+
+	// Normal move
+	{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.86f, 0.9f, 0.93f, 0.95f, 0.96f, 0.97f, 0.98f, 0.99f, 1.0f,	// XY movemnt
+	  0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 },	// Z movement
+
+	// Stirred up by fast vehicle
+	{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.95f, 1.1f, 1.15f, 1.18f, 1.15f, 1.1f, 1.05f, 1.03f, 1.0f,
+	  0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }
+};
+
+void
+CRubbish::Update(void)
+{
+	bool foundGround;
+
+	// FRAMETIME
+	if(bRubbishInvisible)
+		RubbishVisibility = max(RubbishVisibility-5, 0);
+	else
+		RubbishVisibility = min(RubbishVisibility+5, 255);
+
+	// Spawn a new sheet
+	COneSheet *sheet = StartEmptyList.m_next;
+	if(sheet != &EndEmptyList){
+		float spawnDist;
+		float spawnAngle;
+
+		spawnDist = (CGeneral::GetRandomNumber()&0xFF)/256.0f + RUBBISH_MAX_DIST;
+		uint8 r = CGeneral::GetRandomNumber();
+		if(r&1)
+			spawnAngle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
+		else
+			spawnAngle = (r-128)/160.0f + TheCamera.Orientation;
+		sheet->m_basePos.x = TheCamera.GetPosition().x + spawnDist*Sin(spawnAngle);
+		sheet->m_basePos.y = TheCamera.GetPosition().y + spawnDist*Cos(spawnAngle);
+		sheet->m_basePos.z = CWorld::FindGroundZFor3DCoord(sheet->m_basePos.x, sheet->m_basePos.y, TheCamera.GetPosition().z, &foundGround) + 0.1f;
+		if(foundGround){
+			// Found ground, so add to statics list
+			sheet->m_angle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
+			sheet->m_state = 1;
+			if(CCullZones::FindAttributesForCoors(sheet->m_basePos, nil) & ATTRZONE_NORAIN)
+				sheet->m_isVisible = false;
+			else
+				sheet->m_isVisible = true;
+			sheet->RemoveFromList();
+			sheet->AddToList(&StartStaticsList);
+		}
+	}
+
+	// Process animation
+	sheet = StartMoversList.m_next;
+	while(sheet != &EndMoversList){
+		uint32 currentTime = CTimer::GetTimeInMilliseconds() - sheet->m_moveStart;
+		if(currentTime < sheet->m_moveDuration){
+			// Animation
+			int step = 16 * currentTime / sheet->m_moveDuration;	// 16 steps in animation
+			int stepTime = sheet->m_moveDuration/16;	// time in each step
+			float s = (float)(currentTime - stepTime*step) / stepTime;	// position on step
+			float t = (float)currentTime / sheet->m_moveDuration;	// position on total animation
+			// factors for xy and z-movment
+			float fxy = aAnimations[sheet->m_animationType][step]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1]*s;
+			float fz = aAnimations[sheet->m_animationType][step+17]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1+17]*s;
+			sheet->m_animatedPos.x = sheet->m_basePos.x + fxy*sheet->m_xDist;
+			sheet->m_animatedPos.y = sheet->m_basePos.y + fxy*sheet->m_yDist;
+			sheet->m_animatedPos.z = (1.0f-t)*sheet->m_basePos.z + t*sheet->m_targetZ + fz*sheet->m_animHeight;
+			sheet->m_angle += CTimer::GetTimeStep()*0.04f;
+			if(sheet->m_angle > 6.28f)
+				sheet->m_angle -= 6.28f;
+			sheet = sheet->m_next;
+		}else{
+			// End of animation, back into statics list
+			sheet->m_basePos.x += sheet->m_xDist;
+			sheet->m_basePos.y += sheet->m_yDist;
+			sheet->m_basePos.z = sheet->m_targetZ;
+			sheet->m_state = 1;
+			sheet->m_isVisible = sheet->m_targetIsVisible;
+
+			COneSheet *next = sheet->m_next;
+			sheet->RemoveFromList();
+			sheet->AddToList(&StartStaticsList);
+			sheet = next;
+		}
+	}
+
+	// Stir up a sheet by wind
+	// FRAMETIME
+	int freq;
+	if(CWeather::Wind < 0.1f)
+		freq = 31;
+	else if(CWeather::Wind < 0.4f)
+		freq = 7;
+	else if(CWeather::Wind < 0.7f)
+		freq = 1;
+	else
+		freq = 0;
+	if((CTimer::GetFrameCounter() & freq) == 0){
+		// Pick a random sheet and set animation state if static
+		int i = CGeneral::GetRandomNumber() % NUM_RUBBISH_SHEETS;
+		if(aSheets[i].m_state == 1){
+			aSheets[i].m_moveStart = CTimer::GetTimeInMilliseconds();
+			aSheets[i].m_moveDuration = CWeather::Wind*1500.0f + 1000.0f;
+			aSheets[i].m_animHeight = 0.2f;
+			aSheets[i].m_xDist = 3.0f*CWeather::Wind;
+			aSheets[i].m_yDist = 3.0f*CWeather::Wind;
+			// Check if target position is ok
+			float tx = aSheets[i].m_basePos.x + aSheets[i].m_xDist;
+			float ty = aSheets[i].m_basePos.y + aSheets[i].m_yDist;
+			float tz = aSheets[i].m_basePos.z + 3.0f;
+			aSheets[i].m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, &foundGround) + 0.1f;
+			if(CCullZones::FindAttributesForCoors(CVector(tx, ty, aSheets[i].m_targetZ), nil) & ATTRZONE_NORAIN)
+				aSheets[i].m_targetIsVisible = false;
+			else
+				aSheets[i].m_targetIsVisible = true;
+			if(foundGround){
+				// start animation
+				aSheets[i].m_state = 2;
+				aSheets[i].m_animationType = 1;
+				aSheets[i].RemoveFromList();
+				aSheets[i].AddToList(&StartMoversList);
+			}
+		}
+	}
+
+	// Remove sheets that are too far away
+	int i = (CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4))*4;
+	int last = ((CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4)) + 1)*4;
+	for(; i < last; i++){
+		if(aSheets[i].m_state == 1 &&
+		   (aSheets[i].m_basePos - TheCamera.GetPosition()).MagnitudeSqr2D() > SQR(RUBBISH_MAX_DIST+1.0f)){
+			aSheets[i].m_state = 0;
+			aSheets[i].RemoveFromList();
+			aSheets[i].AddToList(&StartEmptyList);
+		}
+	}
+}
+
+void
+CRubbish::SetVisibility(bool visible)
+{
+	bRubbishInvisible = !visible;
+}
+
+void
+CRubbish::Init(void)
+{
+	int i;
+	for(i = 0; i < NUM_RUBBISH_SHEETS; i++){
+		aSheets[i].m_state = 0;
+		if(i < NUM_RUBBISH_SHEETS-1)
+			aSheets[i].m_next = &aSheets[i+1];
+		else
+			aSheets[i].m_next = &EndEmptyList;
+		if(i > 0)
+			aSheets[i].m_prev = &aSheets[i-1];
+		else
+			aSheets[i].m_prev = &StartEmptyList;
+	}
+
+	StartEmptyList.m_next = &aSheets[0];
+	StartEmptyList.m_prev = nil;
+	EndEmptyList.m_next = nil;
+	EndEmptyList.m_prev = &aSheets[NUM_RUBBISH_SHEETS-1];
+
+	StartStaticsList.m_next = &EndStaticsList;
+	StartStaticsList.m_prev = nil;
+	EndStaticsList.m_next = nil;
+	EndStaticsList.m_prev = &StartStaticsList;
+
+	StartMoversList.m_next = &EndMoversList;
+	StartMoversList.m_prev = nil;
+	EndMoversList.m_next = nil;
+	EndMoversList.m_prev = &StartMoversList;
+
+	// unused
+	RwIm3DVertexSetU(&RubbishVertices[0], 0.0f);
+	RwIm3DVertexSetV(&RubbishVertices[0], 0.0f);
+	RwIm3DVertexSetU(&RubbishVertices[1], 1.0f);
+	RwIm3DVertexSetV(&RubbishVertices[1], 0.0f);
+	RwIm3DVertexSetU(&RubbishVertices[2], 0.0f);
+	RwIm3DVertexSetV(&RubbishVertices[2], 1.0f);
+	RwIm3DVertexSetU(&RubbishVertices[3], 1.0f);
+	RwIm3DVertexSetV(&RubbishVertices[3], 1.0f);
+
+	// unused
+	RubbishIndexList2[0] = 0;
+	RubbishIndexList2[1] = 2;
+	RubbishIndexList2[2] = 1;
+	RubbishIndexList2[3] = 1;
+	RubbishIndexList2[4] = 2;
+	RubbishIndexList2[5] = 3;
+
+	RubbishIndexList[0] = 0;
+	RubbishIndexList[1] = 1;
+	RubbishIndexList[2] = 2;
+	RubbishIndexList[3] = 1;
+	RubbishIndexList[4] = 3;
+	RubbishIndexList[5] = 2;
+
+	CTxdStore::PushCurrentTxd();
+	int slot = CTxdStore::FindTxdSlot("particle");
+	CTxdStore::SetCurrentTxd(slot);
+	gpRubbishTexture[0] = RwTextureRead("gameleaf01_64", nil);
+	gpRubbishTexture[1] = RwTextureRead("gameleaf02_64", nil);
+	gpRubbishTexture[2] = RwTextureRead("newspaper01_64", nil);
+	gpRubbishTexture[3] = RwTextureRead("newspaper02_64", nil);
+	CTxdStore::PopCurrentTxd();
+	RubbishVisibility = 255;
+	bRubbishInvisible = false;
+}
+
+void
+CRubbish::Shutdown(void)
+{
+	RwTextureDestroy(gpRubbishTexture[0]);
+	RwTextureDestroy(gpRubbishTexture[1]);
+	RwTextureDestroy(gpRubbishTexture[2]);
+	RwTextureDestroy(gpRubbishTexture[3]);
+}
diff --git a/src/render/Rubbish.h b/src/render/Rubbish.h
index 17323694..2be592fe 100644
--- a/src/render/Rubbish.h
+++ b/src/render/Rubbish.h
@@ -2,13 +2,50 @@
 
 class CVehicle;
 
+enum {
+	// NB: not all values are allowed, check the code
+	NUM_RUBBISH_SHEETS = 64
+};
+
+class COneSheet
+{
+public:
+	CVector m_basePos;
+	CVector m_animatedPos;
+	float m_targetZ;
+	int8 m_state;
+	int8 m_animationType;
+	uint32 m_moveStart;
+	uint32 m_moveDuration;
+	float m_animHeight;
+	float m_xDist;
+	float m_yDist;
+	float m_angle;
+	bool m_isVisible;
+	bool m_targetIsVisible;
+	COneSheet *m_next;
+	COneSheet *m_prev;
+
+	void AddToList(COneSheet *list);
+	void RemoveFromList(void);
+};
+
 class CRubbish
 {
+	static bool bRubbishInvisible;
+	static int RubbishVisibility;
+	static COneSheet aSheets[NUM_RUBBISH_SHEETS];
+	static COneSheet StartEmptyList;
+	static COneSheet EndEmptyList;
+	static COneSheet StartStaticsList;
+	static COneSheet EndStaticsList;
+	static COneSheet StartMoversList;
+	static COneSheet EndMoversList;
 public:
 	static void Render(void);
 	static void StirUp(CVehicle *veh);	// CAutomobile on PS2
 	static void Update(void);
-	static void SetVisibility(bool);
+	static void SetVisibility(bool visible);
 	static void Init(void);
 	static void Shutdown(void);
 };

From 1207c2ce6face0d9f00666196b85739e7783f8d8 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 7 Apr 2020 12:33:14 +0200
Subject: [PATCH 2/8] implemented CShinyTexts

---
 src/core/config.h        |   1 +
 src/render/Shadows.h     |  11 ++-
 src/render/SpecialFX.cpp | 158 ++++++++++++++++++++++++++++++++++++++-
 src/render/SpecialFX.h   | 141 ++++++++++++++++++++--------------
 4 files changed, 251 insertions(+), 60 deletions(-)

diff --git a/src/core/config.h b/src/core/config.h
index d813a1f2..2422ab13 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -73,6 +73,7 @@ enum Config {
 	NUMCORONAS = 56,
 	NUMPOINTLIGHTS = 32,
 	NUM3DMARKERS = 32,
+	NUMSHINYTEXTS = 32,
 	NUMMONEYMESSAGES = 16,
 	NUMPICKUPMESSAGES = 16,
 	NUMBULLETTRACES = 16,
diff --git a/src/render/Shadows.h b/src/render/Shadows.h
index 982cc463..fb41ebbc 100644
--- a/src/render/Shadows.h
+++ b/src/render/Shadows.h
@@ -175,11 +175,18 @@ public:
 	static void RenderIndicatorShadow        (uint32 nID, uint8 ShadowType, RwTexture *pTexture,  CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity);
 };
 
-extern RwTexture *&gpBloodPoolTex;
+extern RwTexture *&gpShadowCarTex;
+extern RwTexture *&gpShadowPedTex;
+extern RwTexture *&gpShadowHeliTex;
 extern RwTexture *&gpShadowExplosionTex;
 extern RwTexture *&gpShadowHeadLightsTex;
-extern RwTexture *&gpGoalTex;
 extern RwTexture *&gpOutline1Tex;
 extern RwTexture *&gpOutline2Tex;
 extern RwTexture *&gpOutline3Tex;
+extern RwTexture *&gpBloodPoolTex;
+extern RwTexture *&gpReflectionTex;
+extern RwTexture *&gpGoalMarkerTex;
+extern RwTexture *&gpWalkDontTex;
 extern RwTexture *&gpCrackedGlassTex;
+extern RwTexture *&gpPostShadowTex;
+extern RwTexture *&gpGoalTex;
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 301ae265..71fca3ba 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -1,6 +1,7 @@
 #include "common.h"
 #include "patcher.h"
 #include "SpecialFX.h"
+#include "RenderBuffer.h"
 #include "Timer.h"
 #include "Sprite.h"
 #include "Font.h"
@@ -12,6 +13,7 @@
 #include "VisibilityPlugins.h"
 #include "World.h"
 #include "Particle.h"
+#include "Shadows.h"
 #include "General.h"
 #include "Camera.h"
 #include "Shadows.h"
@@ -26,7 +28,7 @@ WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint
 
 
 CBulletTrace (&CBulletTraces::aTraces)[NUMBULLETTRACES] = *(CBulletTrace(*)[NUMBULLETTRACES])*(uintptr*)0x72B1B8;
-RxObjSpace3DVertex (&TraceVertices)[6] = *(RxObjSpace3DVertex(*)[6])*(uintptr*)0x649884;
+RxObjSpace3DVertex (&TraceVertices)[6] = *(RxObjSpace3DVertex(*)[6])*(uintptr*)0x649884;
 RwImVertexIndex (&TraceIndexList)[12] = *(RwImVertexIndex(*)[12])*(uintptr*)0x64986C;
 
 void CBulletTraces::Init(void)
@@ -81,8 +83,8 @@ void CBulletTraces::Render(void)
 			RwIm3DEnd();
 		}
 	}
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1);
-	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)5);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)5);
 	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)6);
 }
 
@@ -402,6 +404,151 @@ C3dMarkers::Update()
 {
 }
 
+
+int CShinyTexts::NumShinyTexts;
+CShinyText CShinyTexts::aShinyTexts[NUMSHINYTEXTS];
+
+void
+CShinyTexts::Init(void)
+{
+	NumShinyTexts = 0;
+}
+
+void
+CShinyTexts::RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
+	float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
+	uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist)
+{
+	if(NumShinyTexts >= NUMSHINYTEXTS)
+		return;
+
+	aShinyTexts[NumShinyTexts].m_camDist = (p0 - TheCamera.GetPosition()).Magnitude();
+	if(aShinyTexts[NumShinyTexts].m_camDist > maxDist)
+		return;
+	aShinyTexts[NumShinyTexts].m_verts[0] = p0;
+	aShinyTexts[NumShinyTexts].m_verts[1] = p1;
+	aShinyTexts[NumShinyTexts].m_verts[2] = p2;
+	aShinyTexts[NumShinyTexts].m_verts[3] = p3;
+	aShinyTexts[NumShinyTexts].m_texCoords[0].x = u0;
+	aShinyTexts[NumShinyTexts].m_texCoords[0].y = v0;
+	aShinyTexts[NumShinyTexts].m_texCoords[1].x = u1;
+	aShinyTexts[NumShinyTexts].m_texCoords[1].y = v1;
+	aShinyTexts[NumShinyTexts].m_texCoords[2].x = u2;
+	aShinyTexts[NumShinyTexts].m_texCoords[2].y = v2;
+	aShinyTexts[NumShinyTexts].m_texCoords[3].x = u3;
+	aShinyTexts[NumShinyTexts].m_texCoords[3].y = v3;
+	aShinyTexts[NumShinyTexts].m_type = type;
+	aShinyTexts[NumShinyTexts].m_red = red;
+	aShinyTexts[NumShinyTexts].m_green = green;
+	aShinyTexts[NumShinyTexts].m_blue = blue;
+	// Fade out at half the max dist
+	float halfDist = maxDist*0.5f;
+	if(aShinyTexts[NumShinyTexts].m_camDist > halfDist){
+		float f = 1.0f - (aShinyTexts[NumShinyTexts].m_camDist - halfDist)/halfDist;
+		aShinyTexts[NumShinyTexts].m_red *= f;
+		aShinyTexts[NumShinyTexts].m_green *= f;
+		aShinyTexts[NumShinyTexts].m_blue *= f;
+	}
+
+	NumShinyTexts++;
+}
+
+void
+CShinyTexts::Render(void)
+{
+	int i, ix, v;
+	RwTexture *lastTex = nil;
+
+	if(NumShinyTexts == 0)
+		return;
+
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+
+	TempBufferVerticesStored = 0;
+	TempBufferIndicesStored = 0;
+
+	for(i = 0; i < NumShinyTexts; i++){
+		if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-64 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-62)
+			RenderOutGeometryBuffer();
+
+		uint8 r = aShinyTexts[i].m_red;
+		uint8 g = aShinyTexts[i].m_green;
+		uint8 b = aShinyTexts[i].m_blue;
+
+		switch(aShinyTexts[i].m_type){
+		case SHINYTEXT_WALK:
+			if(lastTex != gpWalkDontTex){
+				RenderOutGeometryBuffer();
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpWalkDontTex));
+				lastTex = gpWalkDontTex;
+			}
+	quad:
+			v = TempBufferVerticesStored;
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_verts[0].x, aShinyTexts[i].m_verts[0].y, aShinyTexts[i].m_verts[0].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].y);
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_verts[1].x, aShinyTexts[i].m_verts[1].y, aShinyTexts[i].m_verts[1].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].y);
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_verts[2].x, aShinyTexts[i].m_verts[2].y, aShinyTexts[i].m_verts[2].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].y);
+			RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], r, g, b, 255);
+			RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_verts[3].x, aShinyTexts[i].m_verts[3].y, aShinyTexts[i].m_verts[3].z);
+			RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].x);
+			RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].y);
+			ix = TempBufferIndicesStored;
+			TempBufferRenderIndexList[ix+0] = 0 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+1] = 1 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+2] = 2 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+3] = 2 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+4] = 1 + TempBufferVerticesStored;
+			TempBufferRenderIndexList[ix+5] = 3 + TempBufferVerticesStored;
+			TempBufferVerticesStored += 4;
+			TempBufferIndicesStored += 6;
+			break;
+
+		case SHINYTEXT_FLAT:
+			if(lastTex != nil){
+				RenderOutGeometryBuffer();
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+				lastTex = nil;
+			}
+			goto quad;
+		}
+	}
+
+	RenderOutGeometryBuffer();
+	NumShinyTexts = 0;
+
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+}
+
+void
+CShinyTexts::RenderOutGeometryBuffer(void)
+{
+	if(TempBufferIndicesStored != 0){
+		LittleTest();
+		if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+			RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+			RwIm3DEnd();
+		}
+		TempBufferVerticesStored = 0;
+		TempBufferIndicesStored = 0;
+	}
+}
+
+
+
 #define MONEY_MESSAGE_LIFETIME_MS 2000
 
 CMoneyMessage CMoneyMessages::aMoneyMessages[NUMMONEYMESSAGES];
@@ -564,6 +711,11 @@ STARTPATCHES
 	InjectHook(0x51B400, C3dMarkers::Render, PATCH_JUMP);
 	InjectHook(0x51B3B0, C3dMarkers::Shutdown, PATCH_JUMP);
 	
+	InjectHook(0x51A5A0, CShinyTexts::Init, PATCH_JUMP);
+	InjectHook(0x51AAB0, CShinyTexts::RegisterOne, PATCH_JUMP);
+	InjectHook(0x51A5B0, CShinyTexts::Render, PATCH_JUMP);
+	InjectHook(0x51AA50, CShinyTexts::RenderOutGeometryBuffer, PATCH_JUMP);
+
 	InjectHook(0x51AF70, CMoneyMessages::Init, PATCH_JUMP);
 	InjectHook(0x51B030, CMoneyMessages::Render, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index fc155a53..22ee502e 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -57,27 +57,27 @@ enum
 
 
 class C3dMarker
-{
-public:
-	CMatrix m_Matrix;
-	RpAtomic *m_pAtomic;
-	RpMaterial *m_pMaterial;
-	uint16 m_nType;
-	bool m_bIsUsed;
-	uint32 m_nIdentifier;
-	RwRGBA m_Color;
-	uint16 m_nPulsePeriod;
-	int16 m_nRotateRate;
-	uint32 m_nStartTime;
-	float m_fPulseFraction;
-	float m_fStdSize;
-	float m_fSize;
-	float m_fBrightness;
-	float m_fCameraRange;
-
-	bool AddMarker(uint32 identifier, uint16 type, float fSize, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
-	void DeleteMarkerObject();
-	void Render();
+{
+public:
+	CMatrix m_Matrix;
+	RpAtomic *m_pAtomic;
+	RpMaterial *m_pMaterial;
+	uint16 m_nType;
+	bool m_bIsUsed;
+	uint32 m_nIdentifier;
+	RwRGBA m_Color;
+	uint16 m_nPulsePeriod;
+	int16 m_nRotateRate;
+	uint32 m_nStartTime;
+	float m_fPulseFraction;
+	float m_fStdSize;
+	float m_fSize;
+	float m_fBrightness;
+	float m_fCameraRange;
+
+	bool AddMarker(uint32 identifier, uint16 type, float fSize, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
+	void DeleteMarkerObject();
+	void Render();
 };
 
 class C3dMarkers
@@ -87,42 +87,73 @@ public:
 	static void Shutdown();
 	static C3dMarker *PlaceMarker(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
 	static void PlaceMarkerSet(uint32 id, uint16 type, CVector &pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
-	static void Render();
+	static void Render();
 	static void Update();
 
 	static C3dMarker(&m_aMarkerArray)[NUM3DMARKERS];
 	static int32 &NumActiveMarkers;
 	static RpClump* (&m_pRpClumpArray)[NUMMARKERTYPES];
-};
-
-class CMoneyMessage
-{
-	friend class CMoneyMessages;
-
-	uint32	m_nTimeRegistered;
-	CVector	m_vecPosition;
-	wchar	m_aText[16];
-	CRGBA	m_Colour;
-	float	m_fSize;
-	float	m_fOpacity;
-public:
-	void Render();
-};
-
-class CMoneyMessages
-{
-	static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
-public:
-	static void Init();
-	static void Render();
-	static void	RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity);
-};
-
-class CSpecialParticleStuff
-{
-	static uint32 BoatFromStart;
-public:
-	static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
-	static void StartBoatFoamAnimation();
-	static void UpdateBoatFoamAnimation(CMatrix*);
-};
+};
+
+enum
+{
+	SHINYTEXT_WALK = 1,
+	SHINYTEXT_FLAT
+};
+
+class CShinyText
+{
+public:
+	CVector m_verts[4];
+	CVector2D m_texCoords[4];
+	float m_camDist;
+	uint8 m_type;
+	uint8 m_red;
+	uint8 m_green;
+	uint8 m_blue;
+};
+
+class CShinyTexts
+{
+	static int NumShinyTexts;
+	static CShinyText aShinyTexts[NUMSHINYTEXTS];
+public:
+	static void Init(void);
+	static void RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
+		float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
+		uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist);
+	static void Render(void);
+	static void RenderOutGeometryBuffer(void);
+};
+
+class CMoneyMessage
+{
+	friend class CMoneyMessages;
+
+	uint32	m_nTimeRegistered;
+	CVector	m_vecPosition;
+	wchar	m_aText[16];
+	CRGBA	m_Colour;
+	float	m_fSize;
+	float	m_fOpacity;
+public:
+	void Render();
+};
+
+class CMoneyMessages
+{
+	static CMoneyMessage aMoneyMessages[NUMMONEYMESSAGES];
+public:
+	static void Init();
+	static void Render();
+	static void	RegisterOne(CVector vecPos, const char *pText, uint8 bRed, uint8 bGreen, uint8 bBlue, float fSize, float fOpacity);
+};
+
+class CSpecialParticleStuff
+{
+	static uint32 BoatFromStart;
+public:
+	static void CreateFoamAroundObject(CMatrix*, float, float, float, int32);
+	static void StartBoatFoamAnimation();
+	static void UpdateBoatFoamAnimation(CMatrix*);
+};

From 51512db0063385bfb823edee150e3cc59eae7b1b Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 7 Apr 2020 16:48:49 +0200
Subject: [PATCH 3/8] implemented CRubbish

---
 README.md                   |  13 +-
 src/core/config.h           |   1 +
 src/render/SpecialFX.cpp    | 235 +++++++++++++++++++++++++++++++++++-
 src/render/SpecialFX.h      |  58 ++++++++-
 src/vehicles/Automobile.cpp |  18 +--
 5 files changed, 303 insertions(+), 22 deletions(-)

diff --git a/README.md b/README.md
index 5d81e0b2..d63b2908 100644
--- a/README.md
+++ b/README.md
@@ -40,12 +40,8 @@ to reverse at the time, calling the original functions is acceptable.
 ```
 cAudioManager - WIP
 CBoat
-CBrightLights
 CBulletInfo
-CCullZone - only mobile stuff
-CCullZones - only mobile stuff
 CExplosion
-CFileLoader - almost done
 CMenuManager - WIP
 CMotionBlurStreaks
 CObject
@@ -56,7 +52,6 @@ CPools - save/loading
 CRecordDataForChase
 CRecordDataForGame
 CRoadBlocks
-CSceneEdit
 CSkidmarks
 CSpecialFX
 CStats
@@ -67,6 +62,14 @@ CWorld
 GenericLoad
 ```
 
+The following classes have only unused or practically unused code left:
+```
+CCullZone - only mobile stuff
+CCullZones - only mobile stuff
+CFileLoader - almost done
+CSceneEdit
+```
+
 ### Coding style
 
 I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style),
diff --git a/src/core/config.h b/src/core/config.h
index 2422ab13..1dc6abe9 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -73,6 +73,7 @@ enum Config {
 	NUMCORONAS = 56,
 	NUMPOINTLIGHTS = 32,
 	NUM3DMARKERS = 32,
+	NUMBRIGHTLIGHTS = 32,
 	NUMSHINYTEXTS = 32,
 	NUMMONEYMESSAGES = 16,
 	NUMPICKUPMESSAGES = 16,
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 71fca3ba..f126e197 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -117,8 +117,6 @@ void CBulletTrace::Update(void)
 	m_framesInUse++;
 }
 
-WRAPPER void CBrightLights::RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1, uint8 unk2, uint8 unk3) { EAXJMP(0x51A410); }
-
 RpAtomic *
 MarkerAtomicCB(RpAtomic *atomic, void *data)
 {
@@ -405,6 +403,234 @@ C3dMarkers::Update()
 }
 
 
+#define BRIGHTLIGHTS_MAX_DIST (60.0f)	// invisible beyond this
+#define BRIGHTLIGHTS_FADE_DIST (45.0f)	// strongest between these two
+#define CARLIGHTS_MAX_DIST (30.0f)
+#define CARLIGHTS_FADE_DIST (15.0f)	// 31 for close lights
+
+int CBrightLights::NumBrightLights;
+CBrightLight CBrightLights::aBrightLights[NUMBRIGHTLIGHTS];
+
+void
+CBrightLights::Init(void)
+{
+	NumBrightLights = 0;
+}
+
+void
+CBrightLights::RegisterOne(CVector pos, CVector up, CVector side, CVector front,
+	uint8 type, uint8 red, uint8 green, uint8 blue)
+{
+	if(NumBrightLights >= NUMBRIGHTLIGHTS)
+		return;
+
+	aBrightLights[NumBrightLights].m_camDist = (pos - TheCamera.GetPosition()).Magnitude();
+	if(aBrightLights[NumBrightLights].m_camDist > BRIGHTLIGHTS_MAX_DIST)
+		return;
+
+	aBrightLights[NumBrightLights].m_pos = pos;
+	aBrightLights[NumBrightLights].m_up = up;
+	aBrightLights[NumBrightLights].m_side = side;
+	aBrightLights[NumBrightLights].m_front = front;
+	aBrightLights[NumBrightLights].m_type = type;
+	aBrightLights[NumBrightLights].m_red = red;
+	aBrightLights[NumBrightLights].m_green = green;
+	aBrightLights[NumBrightLights].m_blue = blue;
+
+	NumBrightLights++;
+}
+
+static float TrafficLightsSide[6] = { -0.09f, 0.09f, 0.162f, 0.09f, -0.09f, -0.162f };
+static float TrafficLightsUp[6] = { 0.162f, 0.162f, 0.0f, -0.162f, -0.162f, 0.0f };
+static float LongCarHeadLightsSide[8] = { -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f };
+static float LongCarHeadLightsFront[8] = { 0.1f, 0.1f, -0.1f, -0.1f, 0.1f, 0.1f, -0.1f, -0.1f };
+static float LongCarHeadLightsUp[8] = { 0.1f, 0.1f, 0.1f, 0.1f, -0.1f, -0.1f, -0.1f, -0.1f };
+static float SmallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
+static float SmallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
+static float SmallCarHeadLightsUp[8] = { 0.08f, 0.08f, 0.08f, 0.08f, -0.08f, -0.08f, -0.08f, -0.08f };
+static float BigCarHeadLightsSide[8] = { -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f };
+static float BigCarHeadLightsFront[8] = { 0.15f, 0.15f, -0.15f, -0.15f, 0.15f, 0.15f, -0.15f, -0.15f };
+static float BigCarHeadLightsUp[8] = { 0.15f, 0.15f, 0.15f, 0.15f, -0.15f, -0.15f, -0.15f, -0.15f };
+static float TallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
+static float TallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
+static float TallCarHeadLightsUp[8] = { 0.2f, 0.2f, 0.2f, 0.2f, -0.2f, -0.2f, -0.2f, -0.2f };
+static float SirenLightsSide[6] = { -0.04f, 0.04f, 0.06f, 0.04f, -0.04f, -0.06f };
+static float SirenLightsUp[6] = { 0.06f, 0.06f, 0.0f, -0.06f, -0.06f, 0.0f };
+static RwImVertexIndex TrafficLightIndices[4*3] = { 0, 1, 5,  1, 2, 3,  1, 3, 4,  1, 4, 5 };
+static RwImVertexIndex CubeIndices[12*3] = {
+	0, 2, 1,  1, 2, 3,  3, 5, 1,  3, 7, 5,
+	2, 7, 3,  2, 6, 7,  4, 0, 1,  4, 1, 5,
+	6, 0, 4,  6, 2, 0,  6, 5, 7,  6, 4, 5
+};
+
+void
+CBrightLights::Render(void)
+{
+	int i, j;
+	CVector pos;
+
+	if(NumBrightLights == 0)
+		return;
+
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+
+	for(i = 0; i < NumBrightLights; i++){
+		if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-40 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-40)
+			RenderOutGeometryBuffer();
+
+		int r, g, b, a;
+		float flicker = (CGeneral::GetRandomNumber()&0xFF) * 0.2f;
+		switch(aBrightLights[i].m_type){
+		case BRIGHTLIGHT_TRAFFIC_GREEN:
+			r = flicker; g = 255; b = flicker;
+			break;
+		case BRIGHTLIGHT_TRAFFIC_YELLOW:
+			r = 255; g = 128; b = flicker;
+			break;
+		case BRIGHTLIGHT_TRAFFIC_RED:
+			r = 255; g = flicker; b = flicker;
+			break;
+
+		case BRIGHTLIGHT_FRONT_LONG:
+		case BRIGHTLIGHT_FRONT_SMALL:
+		case BRIGHTLIGHT_FRONT_BIG:
+		case BRIGHTLIGHT_FRONT_TALL:
+			r = 255; g = 255; b = 255;
+			break;
+
+		case BRIGHTLIGHT_REAR_LONG:
+		case BRIGHTLIGHT_REAR_SMALL:
+		case BRIGHTLIGHT_REAR_BIG:
+		case BRIGHTLIGHT_REAR_TALL:
+			r = 255; g = flicker; b = flicker;
+			break;
+
+		case BRIGHTLIGHT_SIREN:
+			r = aBrightLights[i].m_red;
+			g = aBrightLights[i].m_green;
+			b = aBrightLights[i].m_blue;
+			break;
+		}
+
+		if(aBrightLights[i].m_camDist < BRIGHTLIGHTS_FADE_DIST)
+			a = 255;
+		else
+			a = 255*(1.0f - (aBrightLights[i].m_camDist-BRIGHTLIGHTS_FADE_DIST)/(BRIGHTLIGHTS_MAX_DIST-BRIGHTLIGHTS_FADE_DIST));
+		// fade car lights down to 31 as they come near
+		if(aBrightLights[i].m_type >= BRIGHTLIGHT_FRONT_LONG && aBrightLights[i].m_type <= BRIGHTLIGHT_REAR_TALL){
+			if(aBrightLights[i].m_camDist < CARLIGHTS_FADE_DIST)
+				a = 31;
+			else if(aBrightLights[i].m_camDist < CARLIGHTS_MAX_DIST)
+				a = 31 + (255-31)*((aBrightLights[i].m_camDist-CARLIGHTS_FADE_DIST)/(CARLIGHTS_MAX_DIST-CARLIGHTS_FADE_DIST));
+		}
+
+		switch(aBrightLights[i].m_type){
+		case BRIGHTLIGHT_TRAFFIC_GREEN:
+		case BRIGHTLIGHT_TRAFFIC_YELLOW:
+		case BRIGHTLIGHT_TRAFFIC_RED:
+			for(j = 0; j < 6; j++){
+				pos = TrafficLightsSide[j]*aBrightLights[i].m_side +
+					TrafficLightsUp[j]*aBrightLights[i].m_up +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 4*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 6;
+			TempBufferIndicesStored += 4*3;
+			break;
+
+		case BRIGHTLIGHT_FRONT_LONG:
+		case BRIGHTLIGHT_REAR_LONG:
+			for(j = 0; j < 8; j++){
+				pos = LongCarHeadLightsSide[j]*aBrightLights[i].m_side +
+					LongCarHeadLightsUp[j]*aBrightLights[i].m_up +
+					LongCarHeadLightsFront[j]*aBrightLights[i].m_front +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 12*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 8;
+			TempBufferIndicesStored += 12*3;
+			break;
+
+		case BRIGHTLIGHT_FRONT_SMALL:
+		case BRIGHTLIGHT_REAR_SMALL:
+			for(j = 0; j < 8; j++){
+				pos = SmallCarHeadLightsSide[j]*aBrightLights[i].m_side +
+					SmallCarHeadLightsUp[j]*aBrightLights[i].m_up +
+					SmallCarHeadLightsFront[j]*aBrightLights[i].m_front +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 12*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 8;
+			TempBufferIndicesStored += 12*3;
+			break;
+
+		case BRIGHTLIGHT_FRONT_TALL:
+		case BRIGHTLIGHT_REAR_TALL:
+			for(j = 0; j < 8; j++){
+				pos = TallCarHeadLightsSide[j]*aBrightLights[i].m_side +
+					TallCarHeadLightsUp[j]*aBrightLights[i].m_up +
+					TallCarHeadLightsFront[j]*aBrightLights[i].m_front +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 12*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 8;
+			TempBufferIndicesStored += 12*3;
+			break;
+
+		case BRIGHTLIGHT_SIREN:
+			for(j = 0; j < 6; j++){
+				pos = SirenLightsSide[j]*aBrightLights[i].m_side +
+					SirenLightsUp[j]*aBrightLights[i].m_up +
+					aBrightLights[i].m_pos;
+				RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
+				RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
+			}
+			for(j = 0; j < 4*3; j++)
+				TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
+			TempBufferVerticesStored += 6;
+			TempBufferIndicesStored += 4*3;
+			break;
+
+		}
+	}
+
+	RenderOutGeometryBuffer();
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	NumBrightLights = 0;
+}
+
+void
+CBrightLights::RenderOutGeometryBuffer(void)
+{
+	if(TempBufferIndicesStored != 0){
+		LittleTest();
+		if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
+			RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
+			RwIm3DEnd();
+		}
+		TempBufferVerticesStored = 0;
+		TempBufferIndicesStored = 0;
+	}
+}
+
+
+
 int CShinyTexts::NumShinyTexts;
 CShinyText CShinyTexts::aShinyTexts[NUMSHINYTEXTS];
 
@@ -711,6 +937,11 @@ STARTPATCHES
 	InjectHook(0x51B400, C3dMarkers::Render, PATCH_JUMP);
 	InjectHook(0x51B3B0, C3dMarkers::Shutdown, PATCH_JUMP);
 	
+	InjectHook(0x5197A0, CBrightLights::Init, PATCH_JUMP);
+	InjectHook(0x51A410, CBrightLights::RegisterOne, PATCH_JUMP);
+	InjectHook(0x5197B0, CBrightLights::Render, PATCH_JUMP);
+	InjectHook(0x51A3B0, CBrightLights::RenderOutGeometryBuffer, PATCH_JUMP);
+
 	InjectHook(0x51A5A0, CShinyTexts::Init, PATCH_JUMP);
 	InjectHook(0x51AAB0, CShinyTexts::RegisterOne, PATCH_JUMP);
 	InjectHook(0x51A5B0, CShinyTexts::Render, PATCH_JUMP);
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index 22ee502e..1cff55b3 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -37,12 +37,6 @@ public:
 	static void Update(void);
 };
 
-class CBrightLights
-{
-public:
-	static void RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1 = 0, uint8 unk2 = 0, uint8 unk3 = 0);
-};
-
 enum
 {
 	MARKERTYPE_0 = 0,
@@ -95,6 +89,58 @@ public:
 	static RpClump* (&m_pRpClumpArray)[NUMMARKERTYPES];
 };
 
+enum
+{
+	BRIGHTLIGHT_INVALID,
+	BRIGHTLIGHT_TRAFFIC_GREEN,
+	BRIGHTLIGHT_TRAFFIC_YELLOW,
+	BRIGHTLIGHT_TRAFFIC_RED,
+
+	// white
+	BRIGHTLIGHT_FRONT_LONG,
+	BRIGHTLIGHT_FRONT_SMALL,
+	BRIGHTLIGHT_FRONT_BIG,
+	BRIGHTLIGHT_FRONT_TALL,
+
+	// red
+	BRIGHTLIGHT_REAR_LONG,
+	BRIGHTLIGHT_REAR_SMALL,
+	BRIGHTLIGHT_REAR_BIG,
+	BRIGHTLIGHT_REAR_TALL,
+
+	BRIGHTLIGHT_SIREN,	// unused
+
+	BRIGHTLIGHT_FRONT = BRIGHTLIGHT_FRONT_LONG,
+	BRIGHTLIGHT_REAR = BRIGHTLIGHT_REAR_LONG,
+};
+
+class CBrightLight
+{
+public:
+	CVector m_pos;
+	CVector m_up;
+	CVector m_side;
+	CVector m_front;
+	float m_camDist;
+	uint8 m_type;
+	uint8 m_red;
+	uint8 m_green;
+	uint8 m_blue;
+};
+
+class CBrightLights
+{
+	static int NumBrightLights;
+	static CBrightLight aBrightLights[NUMBRIGHTLIGHTS];
+public:
+	static void Init(void);
+	static void RegisterOne(CVector pos, CVector up, CVector side, CVector front,
+		uint8 type, uint8 red = 0, uint8 green = 0, uint8 blue = 0);
+	static void Render(void);
+	static void RenderOutGeometryBuffer(void);
+};
+
+
 enum
 {
 	SHINYTEXT_WALK = 1,
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index e6b936f6..0c8f0dd4 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -253,7 +253,7 @@ CAutomobile::ProcessControl(void)
 
 	ProcessCarAlarm();
 
-	// Scan if this car is committing a crime that the police can see
+	// Scan if this car sees the player committing any crimes
 	if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED &&
 	   m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){
 		switch(GetModelIndex())
@@ -1727,9 +1727,9 @@ CAutomobile::PreRender(void)
 
 		// bright lights
 		if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
-			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + BRIGHTLIGHT_FRONT);
 		if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
-			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + BRIGHTLIGHT_FRONT);
 
 		// Taillights
 
@@ -1798,9 +1798,9 @@ CAutomobile::PreRender(void)
 
 		// bright lights
 		if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
-			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+			CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 		if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
-			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+			CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 
 		// Light shadows
 		if(!alarmOff){
@@ -1873,9 +1873,9 @@ CAutomobile::PreRender(void)
 							CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
 							CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_FRONT);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_FRONT);
 				}else{
 					// braking
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
@@ -1889,9 +1889,9 @@ CAutomobile::PreRender(void)
 							CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
 							CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+						CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 					if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
-						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+						CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
 				}
 			}else{
 				if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)

From daaf443cfaa0532aad8a0ede0cad826c66650593 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 7 Apr 2020 22:26:01 +0200
Subject: [PATCH 4/8] finished CMotionBlurStreaks, CSpecialFX

---
 README.md                |   2 -
 src/core/config.h        |   1 +
 src/core/main.cpp        |  38 +++---
 src/entities/Entity.cpp  |   8 +-
 src/render/SpecialFX.cpp | 259 ++++++++++++++++++++++++++++++++++++---
 src/render/SpecialFX.h   |  31 ++++-
 6 files changed, 294 insertions(+), 45 deletions(-)

diff --git a/README.md b/README.md
index d63b2908..a0e93bae 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,6 @@ CBoat
 CBulletInfo
 CExplosion
 CMenuManager - WIP
-CMotionBlurStreaks
 CObject
 CPacManPickups
 CPad - only cheats
@@ -53,7 +52,6 @@ CRecordDataForChase
 CRecordDataForGame
 CRoadBlocks
 CSkidmarks
-CSpecialFX
 CStats
 CTrafficLights
 CWeapon
diff --git a/src/core/config.h b/src/core/config.h
index 1dc6abe9..dfc454a8 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -78,6 +78,7 @@ enum Config {
 	NUMMONEYMESSAGES = 16,
 	NUMPICKUPMESSAGES = 16,
 	NUMBULLETTRACES = 16,
+	NUMMBLURSTREAKS = 4,
 
 	NUMONSCREENTIMERENTRIES = 1,
 	NUMRADARBLIPS = 32,
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 674527f5..fb5beee0 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -162,17 +162,17 @@ Idle(void *arg)
 	} else {
 		CPointLights::InitPerFrame();
 #ifdef TIMEBARS
-		tbStartTimer(0, "CGame::Process");
+		tbStartTimer(0, "CGame::Process");
 #endif
 		CGame::Process();
 #ifdef TIMEBARS
 		tbEndTimer("CGame::Process");
-		tbStartTimer(0, "DMAudio.Service");
+		tbStartTimer(0, "DMAudio.Service");
 #endif
 		DMAudio.Service();
 
 #ifdef TIMEBARS
-		tbEndTimer("DMAudio.Service");
+		tbEndTimer("DMAudio.Service");
 #endif
 	}
 
@@ -181,18 +181,18 @@ Idle(void *arg)
 #else
 	CPointLights::InitPerFrame();
 #ifdef TIMEBARS
-	tbStartTimer(0, "CGame::Process");
+	tbStartTimer(0, "CGame::Process");
 #endif
 	CGame::Process();
 #ifdef TIMEBARS
 	tbEndTimer("CGame::Process");
-	tbStartTimer(0, "DMAudio.Service");
+	tbStartTimer(0, "DMAudio.Service");
 #endif
 
 	DMAudio.Service();
 
 #ifdef TIMEBARS
-	tbEndTimer("DMAudio.Service");
+	tbEndTimer("DMAudio.Service");
 #endif
 #endif
 
@@ -222,16 +222,16 @@ Idle(void *arg)
 		}
 #endif
 #ifdef TIMEBARS
-		tbStartTimer(0, "CnstrRenderList");
+		tbStartTimer(0, "CnstrRenderList");
 #endif
 		CRenderer::ConstructRenderList();
 #ifdef TIMEBARS
 		tbEndTimer("CnstrRenderList");
-		tbStartTimer(0, "PreRender");
+		tbStartTimer(0, "PreRender");
 #endif
 		CRenderer::PreRender();
 #ifdef TIMEBARS
-		tbEndTimer("PreRender");
+		tbEndTimer("PreRender");
 #endif
 
 		if(CWeather::LightningFlash && !CCullZones::CamNoRain()){
@@ -251,17 +251,17 @@ Idle(void *arg)
 		RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart());
 
 #ifdef TIMEBARS
-		tbStartTimer(0, "RenderScene");
+		tbStartTimer(0, "RenderScene");
 #endif
 		RenderScene();
 #ifdef TIMEBARS
-		tbEndTimer("RenderScene");
+		tbEndTimer("RenderScene");
 #endif
 		RenderDebugShit();
 		RenderEffects();
 
-#ifdef TIMEBARS
-		tbStartTimer(0, "RenderMotionBlur");
+#ifdef TIMEBARS
+		tbStartTimer(0, "RenderMotionBlur");
 #endif
 		if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) &&
 		   TheCamera.m_ScreenReductionPercentage > 0.0f)
@@ -269,11 +269,11 @@ Idle(void *arg)
 		TheCamera.RenderMotionBlur();
 #ifdef TIMEBARS
 		tbEndTimer("RenderMotionBlur");
-		tbStartTimer(0, "Render2dStuff");
+		tbStartTimer(0, "Render2dStuff");
 #endif
 		Render2dStuff();
 #ifdef TIMEBARS
-		tbEndTimer("Render2dStuff");
+		tbEndTimer("Render2dStuff");
 #endif
 	}else{
 		float viewWindow = DEFAULT_VIEWWINDOW;
@@ -293,21 +293,21 @@ Idle(void *arg)
 		DefinedState();
 #endif
 #ifdef TIMEBARS
-	tbStartTimer(0, "RenderMenus");
+	tbStartTimer(0, "RenderMenus");
 #endif
 	RenderMenus();
 #ifdef TIMEBARS
 	tbEndTimer("RenderMenus");
-	tbStartTimer(0, "DoFade");
+	tbStartTimer(0, "DoFade");
 #endif
 	DoFade();
 #ifdef TIMEBARS
 	tbEndTimer("DoFade");
-	tbStartTimer(0, "Render2dStuff-Fade");
+	tbStartTimer(0, "Render2dStuff-Fade");
 #endif
 	Render2dStuffAfterFade();
 #ifdef TIMEBARS
-	tbEndTimer("Render2dStuff-Fade");
+	tbEndTimer("Render2dStuff-Fade");
 #endif
 	CCredits::Render();
 
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 8bec1ac8..7a050818 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -394,13 +394,13 @@ CEntity::PreRender(void)
 			}else if(GetModelIndex() == MI_GRENADE){
 				CMotionBlurStreaks::RegisterStreak((uintptr)this,
 					100, 100, 100,
-					TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(),
-					TheCamera.GetPosition() + 0.07f*TheCamera.GetRight());
+					GetPosition() - 0.07f*TheCamera.GetRight(),
+					GetPosition() + 0.07f*TheCamera.GetRight());
 			}else if(GetModelIndex() == MI_MOLOTOV){
 				CMotionBlurStreaks::RegisterStreak((uintptr)this,
 					0, 100, 0,
-					TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(),
-					TheCamera.GetPosition() + 0.07f*TheCamera.GetRight());
+					GetPosition() - 0.07f*TheCamera.GetRight(),
+					GetPosition() + 0.07f*TheCamera.GetRight());
 			}
 		}else if(GetModelIndex() == MI_MISSILE){
 			CVector pos = GetPosition();
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index f126e197..0d856d9c 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -9,9 +9,12 @@
 #include "TxdStore.h"
 #include "FileMgr.h"
 #include "FileLoader.h"
+#include "Timecycle.h"
 #include "Lights.h"
+#include "ModelIndices.h"
 #include "VisibilityPlugins.h"
 #include "World.h"
+#include "PlayerPed.h"
 #include "Particle.h"
 #include "Shadows.h"
 #include "General.h"
@@ -19,17 +22,247 @@
 #include "Shadows.h"
 #include "main.h"
 
-WRAPPER void CSpecialFX::Render(void) { EAXJMP(0x518DC0); }
-WRAPPER void CSpecialFX::Update(void) { EAXJMP(0x518D40); }
-WRAPPER void CSpecialFX::Init(void) { EAXJMP(0x5189E0); }
-WRAPPER void CSpecialFX::Shutdown(void) { EAXJMP(0x518BE0); }
+RxObjSpace3DVertex StreakVertices[4];
+RwImVertexIndex StreakIndexList[12];
 
-WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2) { EAXJMP(0x519460); }
+RxObjSpace3DVertex TraceVertices[6];
+RwImVertexIndex TraceIndexList[12];
 
 
-CBulletTrace (&CBulletTraces::aTraces)[NUMBULLETTRACES] = *(CBulletTrace(*)[NUMBULLETTRACES])*(uintptr*)0x72B1B8;
-RxObjSpace3DVertex (&TraceVertices)[6] = *(RxObjSpace3DVertex(*)[6])*(uintptr*)0x649884;
-RwImVertexIndex (&TraceIndexList)[12] = *(RwImVertexIndex(*)[12])*(uintptr*)0x64986C;
+void
+CSpecialFX::Init(void)
+{
+	CBulletTraces::Init();
+
+	RwIm3DVertexSetU(&StreakVertices[0], 0.0f);
+	RwIm3DVertexSetV(&StreakVertices[0], 0.0f);
+	RwIm3DVertexSetU(&StreakVertices[1], 1.0f);
+	RwIm3DVertexSetV(&StreakVertices[1], 0.0f);
+	RwIm3DVertexSetU(&StreakVertices[2], 0.0f);
+	RwIm3DVertexSetV(&StreakVertices[2], 0.0f);
+	RwIm3DVertexSetU(&StreakVertices[3], 1.0f);
+	RwIm3DVertexSetV(&StreakVertices[3], 0.0f);
+
+	StreakIndexList[0] = 0;
+	StreakIndexList[1] = 1;
+	StreakIndexList[2] = 2;
+	StreakIndexList[3] = 1;
+	StreakIndexList[4] = 3;
+	StreakIndexList[5] = 2;
+	StreakIndexList[6] = 0;
+	StreakIndexList[7] = 2;
+	StreakIndexList[8] = 1;
+	StreakIndexList[9] = 1;
+	StreakIndexList[10] = 2;
+	StreakIndexList[11] = 3;
+
+	RwIm3DVertexSetRGBA(&TraceVertices[0], 20, 20, 20, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[1], 20, 20, 20, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[2], 70, 70, 70, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[3], 70, 70, 70, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[4], 10, 10, 10, 255);
+	RwIm3DVertexSetRGBA(&TraceVertices[5], 10, 10, 10, 255);
+	RwIm3DVertexSetU(&TraceVertices[0], 0.0);
+	RwIm3DVertexSetV(&TraceVertices[0], 0.0);
+	RwIm3DVertexSetU(&TraceVertices[1], 1.0);
+	RwIm3DVertexSetV(&TraceVertices[1], 0.0);
+	RwIm3DVertexSetU(&TraceVertices[2], 0.0);
+	RwIm3DVertexSetV(&TraceVertices[2], 0.5);
+	RwIm3DVertexSetU(&TraceVertices[3], 1.0);
+	RwIm3DVertexSetV(&TraceVertices[3], 0.5);
+	RwIm3DVertexSetU(&TraceVertices[4], 0.0);
+	RwIm3DVertexSetV(&TraceVertices[4], 1.0);
+	RwIm3DVertexSetU(&TraceVertices[5], 1.0);
+	RwIm3DVertexSetV(&TraceVertices[5], 1.0);
+
+	TraceIndexList[0] = 0;
+	TraceIndexList[1] = 2;
+	TraceIndexList[2] = 1;
+	TraceIndexList[3] = 1;
+	TraceIndexList[4] = 2;
+	TraceIndexList[5] = 3;
+	TraceIndexList[6] = 2;
+	TraceIndexList[7] = 4;
+	TraceIndexList[8] = 3;
+	TraceIndexList[9] = 3;
+	TraceIndexList[10] = 4;
+	TraceIndexList[11] = 5;
+
+	CMotionBlurStreaks::Init();
+	CBrightLights::Init();
+	CShinyTexts::Init();
+	CMoneyMessages::Init();
+	C3dMarkers::Init();
+}
+
+RwObject*
+LookForBatCB(RwObject *object, void *data)
+{
+	static CMatrix MatLTM;
+
+	if(CVisibilityPlugins::GetAtomicModelInfo((RpAtomic*)object) == (CSimpleModelInfo*)data){
+		MatLTM = CMatrix(RwFrameGetLTM(RpAtomicGetFrame((RpAtomic*)object)));
+		CVector p1 = MatLTM * CVector(0.02f, 0.05f, 0.07f);
+		CVector p2 = MatLTM * CVector(0.246f, 0.0325f, 0.796f);
+		CMotionBlurStreaks::RegisterStreak((uintptr)object, 100, 100, 100, p1, p2);
+	}
+	return nil;
+}
+
+void
+CSpecialFX::Update(void)
+{
+	CMotionBlurStreaks::Update();
+	CBulletTraces::Update();
+
+	if(FindPlayerPed() &&
+	   FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT &&
+	   FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING)
+		RwFrameForAllObjects(FindPlayerPed()->GetNodeFrame(PED_HANDR), LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
+}
+
+void
+CSpecialFX::Shutdown(void)
+{
+	C3dMarkers::Shutdown();
+}
+
+void
+CSpecialFX::Render(void)
+{
+	CMotionBlurStreaks::Render();
+	CBulletTraces::Render();
+	CBrightLights::Render();
+	CShinyTexts::Render();
+	CMoneyMessages::Render();
+	C3dMarkers::Render();
+}
+
+CRegisteredMotionBlurStreak CMotionBlurStreaks::aStreaks[NUMMBLURSTREAKS];
+
+void
+CRegisteredMotionBlurStreak::Update(void)
+{
+	int i;
+	bool wasUpdated;
+	bool lastWasUpdated = false;
+	for(i = 2; i > 0; i--){
+		m_pos1[i] = m_pos1[i-1];
+		m_pos2[i] = m_pos2[i-1];
+		m_isValid[i] = m_isValid[i-1];
+		wasUpdated = true;
+		if(!lastWasUpdated && !m_isValid[i])
+			wasUpdated = false;
+		lastWasUpdated = wasUpdated;
+	}
+	m_isValid[0] = false;
+	if(!wasUpdated)
+		m_id = 0;
+}
+
+void
+CRegisteredMotionBlurStreak::Render(void)
+{
+	int i;
+	int a1, a2;
+	for(i = 0; i < 2; i++)
+		if(m_isValid[i] && m_isValid[i+1]){
+			a1 = (255/3)*(3-i)/3;
+			RwIm3DVertexSetRGBA(&StreakVertices[0], m_red, m_green, m_blue, a1);
+			RwIm3DVertexSetRGBA(&StreakVertices[1], m_red, m_green, m_blue, a1);
+			a2 = (255/3)*(3-(i+1))/3;
+			RwIm3DVertexSetRGBA(&StreakVertices[2], m_red, m_green, m_blue, a2);
+			RwIm3DVertexSetRGBA(&StreakVertices[3], m_red, m_green, m_blue, a2);
+			RwIm3DVertexSetPos(&StreakVertices[0], m_pos1[i].x, m_pos1[i].y, m_pos1[i].z);
+			RwIm3DVertexSetPos(&StreakVertices[1], m_pos2[i].x, m_pos2[i].y, m_pos2[i].z);
+			RwIm3DVertexSetPos(&StreakVertices[2], m_pos1[i+1].x, m_pos1[i+1].y, m_pos1[i+1].z);
+			RwIm3DVertexSetPos(&StreakVertices[3], m_pos2[i+1].x, m_pos2[i+1].y, m_pos2[i+1].z);
+			LittleTest();
+			if(RwIm3DTransform(StreakVertices, 4, nil, rwIM3D_VERTEXUV)){
+				RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, StreakIndexList, 12);
+				RwIm3DEnd();
+			}
+		}
+}
+
+void
+CMotionBlurStreaks::Init(void)
+{
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++)
+		aStreaks[i].m_id = 0;
+}
+
+void
+CMotionBlurStreaks::Update(void)
+{
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++)
+		if(aStreaks[i].m_id)
+			aStreaks[i].Update();
+}
+
+void
+CMotionBlurStreaks::RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2)
+{
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++){
+		if(aStreaks[i].m_id == id){
+			// Found a streak from last frame, update
+			aStreaks[i].m_red = r;
+			aStreaks[i].m_green = g;
+			aStreaks[i].m_blue = b;
+			aStreaks[i].m_pos1[0] = p1;
+			aStreaks[i].m_pos2[0] = p2;
+			aStreaks[i].m_isValid[0] = true;
+			return;
+		}
+	}
+	// Find free slot
+	for(i = 0; aStreaks[i].m_id; i++)
+		if(i == NUMMBLURSTREAKS-1)
+			return;
+	// Create a new streak
+	aStreaks[i].m_id = id;
+	aStreaks[i].m_red = r;
+	aStreaks[i].m_green = g;
+	aStreaks[i].m_blue = b;
+	aStreaks[i].m_pos1[0] = p1;
+	aStreaks[i].m_pos2[0] = p2;
+	aStreaks[i].m_isValid[0] = true;
+	aStreaks[i].m_isValid[1] = false;
+	aStreaks[i].m_isValid[2] = false;
+}
+
+void
+CMotionBlurStreaks::Render(void)
+{
+	bool setRenderStates = false;
+	int i;
+	for(i = 0; i < NUMMBLURSTREAKS; i++)
+		if(aStreaks[i].m_id){
+			if(!setRenderStates){
+				RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+				RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+				RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
+				RwRenderStateSet(rwRENDERSTATEFOGCOLOR,
+					(void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
+				RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+				RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+				RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
+ 				setRenderStates = true;
+			}
+			aStreaks[i].Render();
+		}
+	if(setRenderStates){
+		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
+	}
+}
+
+
+CBulletTrace CBulletTraces::aTraces[NUMBULLETTRACES];
 
 void CBulletTraces::Init(void)
 {
@@ -201,9 +434,9 @@ C3dMarker::Render()
 	ReSetAmbientAndDirectionalColours();
 }
 
-C3dMarker(&C3dMarkers::m_aMarkerArray)[NUM3DMARKERS] = *(C3dMarker(*)[NUM3DMARKERS])*(uintptr*)0x72D408;
-int32 &C3dMarkers::NumActiveMarkers = *(int32*)0x8F2A08;
-RpClump* (&C3dMarkers::m_pRpClumpArray)[NUMMARKERTYPES] = *(RpClump*(*)[NUMMARKERTYPES])*(uintptr*)0x8E2888;
+C3dMarker C3dMarkers::m_aMarkerArray[NUM3DMARKERS];
+int32 C3dMarkers::NumActiveMarkers;
+RpClump* C3dMarkers::m_pRpClumpArray[NUMMARKERTYPES];
 
 void
 C3dMarkers::Init()
@@ -627,9 +860,7 @@ CBrightLights::RenderOutGeometryBuffer(void)
 		TempBufferVerticesStored = 0;
 		TempBufferIndicesStored = 0;
 	}
-}
-
-
+}
 
 int CShinyTexts::NumShinyTexts;
 CShinyText CShinyTexts::aShinyTexts[NUMSHINYTEXTS];
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index 1cff55b3..8519ae79 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -9,10 +9,29 @@ public:
 	static void Shutdown(void);
 };
 
-class CMotionBlurStreaks
+class CRegisteredMotionBlurStreak
 {
 public:
-	static void RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
+	uintptr m_id;
+	uint8 m_red;
+	uint8 m_green;
+	uint8 m_blue;
+	CVector m_pos1[3];
+	CVector m_pos2[3];
+	bool m_isValid[3];
+
+	void Update(void);
+	void Render(void);
+};
+
+class CMotionBlurStreaks
+{
+	static CRegisteredMotionBlurStreak aStreaks[NUMMBLURSTREAKS];
+public:
+	static void Init(void);
+	static void Update(void);
+	static void RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
+	static void Render(void);
 };
 
 struct CBulletTrace
@@ -29,7 +48,7 @@ struct CBulletTrace
 class CBulletTraces
 {
 public:
-	static CBulletTrace (&aTraces)[NUMBULLETTRACES];
+	static CBulletTrace aTraces[NUMBULLETTRACES];
 
 	static void Init(void);
 	static void AddTrace(CVector*, CVector*);
@@ -84,9 +103,9 @@ public:
 	static void Render();
 	static void Update();
 
-	static C3dMarker(&m_aMarkerArray)[NUM3DMARKERS];
-	static int32 &NumActiveMarkers;
-	static RpClump* (&m_pRpClumpArray)[NUMMARKERTYPES];
+	static C3dMarker m_aMarkerArray[NUM3DMARKERS];
+	static int32 NumActiveMarkers;
+	static RpClump* m_pRpClumpArray[NUMMARKERTYPES];
 };
 
 enum

From 560fc655388ac8cc017b4127e9444fc8702ffd45 Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Wed, 8 Apr 2020 09:58:08 +0300
Subject: [PATCH 5/8] Small camera fixes

---
 src/control/Replay.cpp |  2 +-
 src/core/Cam.cpp       | 16 ++++----
 src/core/Camera.cpp    | 86 +++++++++++++++++++++---------------------
 src/core/Camera.h      | 23 ++++++++---
 4 files changed, 68 insertions(+), 59 deletions(-)

diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 2e325249..b8e2318d 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -1107,7 +1107,7 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca
 		CStreaming::LoadScene(ff_coord);
 	}
 	if (cam_mode == REPLAYCAMMODE_ASSTORED)
-		TheCamera.CarZoomIndicator = 5.0f;
+		TheCamera.CarZoomIndicator = CAM_ZOOM_CINEMATIC;
 }
 
 void CReplay::StoreStuffInMem(void)
diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index 5b7a53e9..dc9ef74f 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -4672,15 +4672,15 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 	else {
 		switch ((int)TheCamera.CarZoomIndicator) {
 			// near
-		case 1:
+		case CAM_ZOOM_1:
 			zoomModeAlphaOffset = ZmOneAlphaOffsetLCS[alphaArrPos];
 			break;
 			// mid
-		case 2:
+		case CAM_ZOOM_2:
 			zoomModeAlphaOffset = ZmTwoAlphaOffsetLCS[alphaArrPos];
 			break;
 			// far
-		case 3:
+		case CAM_ZOOM_3:
 			zoomModeAlphaOffset = ZmThreeAlphaOffsetLCS[alphaArrPos];
 			break;
 		default:
@@ -4705,14 +4705,12 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 		}
 	} else {
 		// 0.6f = fTestShiftHeliCamTarget
-		TargetCoors.x += 0.6f * car->GetUp().x * colMaxZ;
-		TargetCoors.y += 0.6f * car->GetUp().y * colMaxZ;
-		TargetCoors.z += 0.6f * car->GetUp().z * colMaxZ;
+		TargetCoors += 0.6f * car->GetUp() * colMaxZ;
 	}
 
 	float minDistForVehType = CARCAM_SET[camSetArrPos][4];
 
-	if ((int)TheCamera.CarZoomIndicator == 1 && (camSetArrPos < 2 || camSetArrPos == 7)) {
+	if (TheCamera.CarZoomIndicator == CAM_ZOOM_1 && (camSetArrPos < 2 || camSetArrPos == 7)) {
 		minDistForVehType = minDistForVehType * 0.65f;
 	}
 
@@ -4904,8 +4902,8 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 	//		yMovement = 0.0;
 
 	if (!nextDirectionIsForward) {
-		yMovement = 0.0;
-		xMovement = 0.0;
+		yMovement = 0.0f;
+		xMovement = 0.0f;
 	}
 
 	if (camSetArrPos == 0 || camSetArrPos == 7) {
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 9d927354..46c17cd2 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -65,8 +65,8 @@ bool &bDidWeProcessAnyCinemaCam = *(bool*)0x95CD46;
 #define KEYJUSTDOWN(k) ControlsManager.GetIsKeyboardKeyJustDown((RsKeyCodes)k)
 #define KEYDOWN(k) ControlsManager.GetIsKeyboardKeyDown((RsKeyCodes)k)
 #define CTRLJUSTDOWN(key) \
-	       ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \
-	        (KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+		   ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \
+			(KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
 #define CTRLDOWN(key) ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
 #endif
 
@@ -124,8 +124,8 @@ CCamera::Init(void)
 	m_WideScreenOn = false;
 	m_fFOV_Wide_Screen = 0.0f;
 	m_bRestoreByJumpCut = false;
-	CarZoomIndicator = 2.0f;
-	PedZoomIndicator = 2.0f;
+	CarZoomIndicator = CAM_ZOOM_2;
+	PedZoomIndicator = CAM_ZOOM_2;
 	CarZoomValueSmooth = 0.0f;
 	m_fPedZoomValueSmooth = 0.0f;
 	pTargetEntity = nil;
@@ -623,11 +623,11 @@ CCamera::CamControl(void)
 				if(CPad::GetPad(0)->CycleCameraModeUpJustDown() && !CReplay::IsPlayingBack() &&
 				   (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
 				   !m_WideScreenOn)
-					CarZoomIndicator -= 1.0f;
+					CarZoomIndicator--;
 				if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() &&
 				   (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
 				   !m_WideScreenOn)
-					CarZoomIndicator += 1.0f;
+					CarZoomIndicator++;
 				if(!m_bFailedCullZoneTestPreviously){
 					if(CarZoomIndicator < CAM_ZOOM_1STPRS) CarZoomIndicator = CAM_ZOOM_CINEMATIC;
 					else if(CarZoomIndicator > CAM_ZOOM_CINEMATIC) CarZoomIndicator = CAM_ZOOM_1STPRS;
@@ -812,7 +812,7 @@ CCamera::CamControl(void)
 					else
 						PedZoomIndicator = CAM_ZOOM_TOPDOWN;
 				}else
-					PedZoomIndicator -= 1.0f;
+					PedZoomIndicator--;
 			}
 			if(CPad::GetPad(0)->CycleCameraModeDownJustDown() && !CReplay::IsPlayingBack() &&
 			   (m_bLookingAtPlayer || WhoIsInControlOfTheCamera == CAMCONTROL_OBBE) &&
@@ -823,7 +823,7 @@ CCamera::CamControl(void)
 					else
 						PedZoomIndicator = CAM_ZOOM_TOPDOWN;
 				}else
-					PedZoomIndicator += 1.0f;
+					PedZoomIndicator++;
 			}
 			// disabled obbe's cam here
 			if(PedZoomIndicator < CAM_ZOOM_1) PedZoomIndicator = CAM_ZOOM_TOPDOWN;
@@ -1223,7 +1223,7 @@ CCamera::CamControl(void)
 	   ReqMode == CCam::MODE_1STPERSON_RUNABOUT || ReqMode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
 	   ReqMode == CCam::MODE_FIGHT_CAM_RUNABOUT || ReqMode == CCam::MODE_HELICANNON_1STPERSON ||
 	   WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT ||
-           m_bJustCameOutOfGarage || m_bPlayerIsInGarage)
+		   m_bJustCameOutOfGarage || m_bPlayerIsInGarage)
 		canUseObbeCam = false;
 
 	if(m_bObbeCinematicPedCamOn && canUseObbeCam)
@@ -1468,9 +1468,9 @@ CCamera::CamControl(void)
 
 	// Ped visibility
 	if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
-	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
-	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
-	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) && pTargetEntity->IsPed() ||
+		Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) && pTargetEntity->IsPed() ||
 	   Cams[ActiveCam].Mode == CCam::MODE_FLYBY)
 		FindPlayerPed()->bIsVisible = false;
 	else
@@ -1524,7 +1524,7 @@ CCamera::UpdateTargetEntity(void)
 			cantOpen = false;
 
 		if(PLAYER->GetPedState() == PED_ENTER_CAR && !cantOpen){
-			if(!enteringCar && CarZoomIndicator != 0.0f){
+			if(!enteringCar && CarZoomIndicator != CAM_ZOOM_1STPRS){
 				pTargetEntity = PLAYER->m_pMyVehicle;
 				if(PLAYER->m_pMyVehicle == nil)
 					pTargetEntity = PLAYER;
@@ -1532,7 +1532,7 @@ CCamera::UpdateTargetEntity(void)
 		}
 
 		if((PLAYER->GetPedState() == PED_CARJACK || PLAYER->GetPedState() == PED_OPEN_DOOR) && !cantOpen){
-			if(!enteringCar && CarZoomIndicator != 0.0f)
+			if(!enteringCar && CarZoomIndicator != CAM_ZOOM_1STPRS)
 #ifdef GTA_PS2_STUFF
 // dunno if this has any amazing effects
 			{
@@ -1549,7 +1549,7 @@ CCamera::UpdateTargetEntity(void)
 			pTargetEntity = FindPlayerPed();
 		if(PLAYER->GetPedState() == PED_DRAG_FROM_CAR)
 			pTargetEntity = FindPlayerPed();
-		if(pTargetEntity->IsVehicle() && CarZoomIndicator != 0.0f && FindPlayerPed()->GetPedState() == PED_ARRESTED)
+		if(pTargetEntity->IsVehicle() && CarZoomIndicator != CAM_ZOOM_1STPRS && FindPlayerPed()->GetPedState() == PED_ARRESTED)
 			pTargetEntity = FindPlayerPed();
 	}
 }
@@ -1566,15 +1566,15 @@ CCamera::UpdateSoundDistances(void)
 	int n;
 
 	if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
-	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
-	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
-	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
-	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) &&
+		Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+		Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) &&
 	   pTargetEntity->IsPed())
 		center = GetPosition() + 0.5f*GetForward();
 	else
@@ -1856,14 +1856,14 @@ CCamera::StartTransition(int16 newMode)
 	m_bUseTransitionBeta = false;
 
 	if((Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
-	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
-	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
-	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
-	    Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
-	    Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT) &&
+		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
+		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+		Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+		Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+		Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT) &&
 	   pTargetEntity->IsPed()){
 		float angle = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) - HALFPI;
 		((CPed*)pTargetEntity)->m_fRotationCur = angle;
@@ -2184,12 +2184,12 @@ CCamera::DrawBordersForWideScreen(void)
 
 	CSprite2d::DrawRect(
 		CRect(0.0f, (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f,
-		      SCREEN_WIDTH, 0.0f),
+			  SCREEN_WIDTH, 0.0f),
 		CRGBA(0, 0, 0, 255));
 
 	CSprite2d::DrawRect(
 		CRect(0.0f, SCREEN_HEIGHT,
-		      SCREEN_WIDTH, SCREEN_HEIGHT - (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f),
+			  SCREEN_WIDTH, SCREEN_HEIGHT - (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f),
 		CRGBA(0, 0, 0, 255));
 }
 
@@ -2631,8 +2631,8 @@ CCamera::ProcessObbeCinemaCameraCar(void)
 	if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfCams[OldMode], TimeForNext)){
 		// This is very strange code...
 		for(OldMode = (OldMode+1) % 14;
-		    !TryToStartNewCamMode(SequenceOfCams[OldMode]) && i <= 14;
-		    OldMode = (OldMode+1) % 14)
+			!TryToStartNewCamMode(SequenceOfCams[OldMode]) && i <= 14;
+			OldMode = (OldMode+1) % 14)
 			i++;
 		TimeForNext = CTimer::GetTimeInMilliseconds();
 		if(i >= 14){
@@ -2659,8 +2659,8 @@ CCamera::ProcessObbeCinemaCameraPed(void)
 
 	if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfPedCams[PedOldMode], PedTimeForNext)){
 		for(PedOldMode = (PedOldMode+1) % 5;
-		    !TryToStartNewCamMode(SequenceOfPedCams[PedOldMode]);
-		    PedOldMode = (PedOldMode+1) % 5);
+			!TryToStartNewCamMode(SequenceOfPedCams[PedOldMode]);
+			PedOldMode = (PedOldMode+1) % 5);
 		PedTimeForNext = CTimer::GetTimeInMilliseconds();
 	}
 	bDidWeProcessAnyCinemaCam = true;
@@ -2813,11 +2813,11 @@ CCamera::Process_Train_Camera_Control(void)
 	uint32 node = m_iCurrentTrainCamNode;
 	for(i = 0; i < m_uiNumberOfTrainCamNodes && !found; i++){
 		if(target->IsWithinArea(m_arrTrainCamNode[node].m_cvecMinPointInRange.x,
-		                        m_arrTrainCamNode[node].m_cvecMinPointInRange.y,
-		                        m_arrTrainCamNode[node].m_cvecMinPointInRange.z,
-		                        m_arrTrainCamNode[node].m_cvecMaxPointInRange.x,
-		                        m_arrTrainCamNode[node].m_cvecMaxPointInRange.y,
-		                        m_arrTrainCamNode[node].m_cvecMaxPointInRange.z)){
+								m_arrTrainCamNode[node].m_cvecMinPointInRange.y,
+								m_arrTrainCamNode[node].m_cvecMinPointInRange.z,
+								m_arrTrainCamNode[node].m_cvecMaxPointInRange.x,
+								m_arrTrainCamNode[node].m_cvecMaxPointInRange.y,
+								m_arrTrainCamNode[node].m_cvecMaxPointInRange.z)){
 			m_iCurrentTrainCamNode = node;
 			found = true;
 		}
diff --git a/src/core/Camera.h b/src/core/Camera.h
index c22ba9c8..eca4518a 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -16,12 +16,15 @@ enum
 };
 
 #define DEFAULT_NEAR (0.9f)
-#define CAM_ZOOM_1STPRS (0.0f)
-#define CAM_ZOOM_1 (1.0f)
-#define CAM_ZOOM_2 (2.0f)
-#define CAM_ZOOM_3 (3.0f)
-#define CAM_ZOOM_TOPDOWN (4.0f)
-#define CAM_ZOOM_CINEMATIC (5.0f)
+enum
+{
+	CAM_ZOOM_1STPRS,
+	CAM_ZOOM_1,
+	CAM_ZOOM_2,
+	CAM_ZOOM_3,
+	CAM_ZOOM_TOPDOWN,
+	CAM_ZOOM_CINEMATIC,
+};
 
 #ifdef FREE_CAM // LCS values
 #define FREE_CAR_ZOOM_VALUE_1 (-1.0f)
@@ -412,7 +415,11 @@ uint32    unknown;	// some counter having to do with music
 
 	float CamFrontXNorm;
 	float CamFrontYNorm;
+#if 0  // TODO: FIX_BUGS once GenericLoad is done
+	int32 CarZoomIndicator;
+#else
 	float CarZoomIndicator;
+#endif
 	float CarZoomValue;
 	float CarZoomValueSmooth;
 
@@ -448,7 +455,11 @@ uint32    unknown;	// some counter having to do with music
 	float m_ScreenReductionSpeed;
 	float m_AlphaForPlayerAnim1rstPerson;
 	float Orientation;
+#if 0  // TODO: FIX_BUGS once GenericLoad is done
+	int32 PedZoomIndicator;
+#else
 	float PedZoomIndicator;
+#endif
 	float PlayerExhaustion;
 	float SoundDistUp, SoundDistLeft, SoundDistRight;
 	float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead;

From 7439d6482ffa8ed7de0a6f3fb8fcc2e11401b97d Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Wed, 8 Apr 2020 10:21:40 +0300
Subject: [PATCH 6/8] Reverting tabs back to spaces for aap

---
 src/core/Camera.cpp | 68 ++++++++++++++++++++++-----------------------
 1 file changed, 34 insertions(+), 34 deletions(-)

diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 46c17cd2..00c838cf 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -65,8 +65,8 @@ bool &bDidWeProcessAnyCinemaCam = *(bool*)0x95CD46;
 #define KEYJUSTDOWN(k) ControlsManager.GetIsKeyboardKeyJustDown((RsKeyCodes)k)
 #define KEYDOWN(k) ControlsManager.GetIsKeyboardKeyDown((RsKeyCodes)k)
 #define CTRLJUSTDOWN(key) \
-		   ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \
-			(KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
+	       ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYJUSTDOWN((RsKeyCodes)key) || \
+	        (KEYJUSTDOWN(rsLCTRL) || KEYJUSTDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
 #define CTRLDOWN(key) ((KEYDOWN(rsLCTRL) || KEYDOWN(rsRCTRL)) && KEYDOWN((RsKeyCodes)key))
 #endif
 
@@ -1223,7 +1223,7 @@ CCamera::CamControl(void)
 	   ReqMode == CCam::MODE_1STPERSON_RUNABOUT || ReqMode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
 	   ReqMode == CCam::MODE_FIGHT_CAM_RUNABOUT || ReqMode == CCam::MODE_HELICANNON_1STPERSON ||
 	   WhoIsInControlOfTheCamera == CAMCONTROL_SCRIPT ||
-		   m_bJustCameOutOfGarage || m_bPlayerIsInGarage)
+	   m_bJustCameOutOfGarage || m_bPlayerIsInGarage)
 		canUseObbeCam = false;
 
 	if(m_bObbeCinematicPedCamOn && canUseObbeCam)
@@ -1468,9 +1468,9 @@ CCamera::CamControl(void)
 
 	// Ped visibility
 	if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
-		Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
-		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
-		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) && pTargetEntity->IsPed() ||
+	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) && pTargetEntity->IsPed() ||
 	   Cams[ActiveCam].Mode == CCam::MODE_FLYBY)
 		FindPlayerPed()->bIsVisible = false;
 	else
@@ -1566,15 +1566,15 @@ CCamera::UpdateSoundDistances(void)
 	int n;
 
 	if((Cams[ActiveCam].Mode == CCam::MODE_1STPERSON ||
-		Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
-		Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
-		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
-		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) &&
+	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
+	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER) &&
 	   pTargetEntity->IsPed())
 		center = GetPosition() + 0.5f*GetForward();
 	else
@@ -1856,14 +1856,14 @@ CCamera::StartTransition(int16 newMode)
 	m_bUseTransitionBeta = false;
 
 	if((Cams[ActiveCam].Mode == CCam::MODE_SNIPER ||
-		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
-		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
-		Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
-		Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
-		Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT) &&
+	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER ||
+	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON ||
+	    Cams[ActiveCam].Mode == CCam::MODE_SNIPER_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_M16_1STPERSON_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_FIGHT_CAM_RUNABOUT ||
+	    Cams[ActiveCam].Mode == CCam::MODE_HELICANNON_1STPERSON ||
+	    Cams[ActiveCam].Mode == CCam::MODE_1STPERSON_RUNABOUT) &&
 	   pTargetEntity->IsPed()){
 		float angle = CGeneral::GetATanOfXY(Cams[ActiveCam].Front.x, Cams[ActiveCam].Front.y) - HALFPI;
 		((CPed*)pTargetEntity)->m_fRotationCur = angle;
@@ -2184,12 +2184,12 @@ CCamera::DrawBordersForWideScreen(void)
 
 	CSprite2d::DrawRect(
 		CRect(0.0f, (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f,
-			  SCREEN_WIDTH, 0.0f),
+		      SCREEN_WIDTH, 0.0f),
 		CRGBA(0, 0, 0, 255));
 
 	CSprite2d::DrawRect(
 		CRect(0.0f, SCREEN_HEIGHT,
-			  SCREEN_WIDTH, SCREEN_HEIGHT - (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f),
+		      SCREEN_WIDTH, SCREEN_HEIGHT - (SCREEN_HEIGHT/2) * m_ScreenReductionPercentage/100.0f - 8.0f),
 		CRGBA(0, 0, 0, 255));
 }
 
@@ -2631,8 +2631,8 @@ CCamera::ProcessObbeCinemaCameraCar(void)
 	if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfCams[OldMode], TimeForNext)){
 		// This is very strange code...
 		for(OldMode = (OldMode+1) % 14;
-			!TryToStartNewCamMode(SequenceOfCams[OldMode]) && i <= 14;
-			OldMode = (OldMode+1) % 14)
+		    !TryToStartNewCamMode(SequenceOfCams[OldMode]) && i <= 14;
+		    OldMode = (OldMode+1) % 14)
 			i++;
 		TimeForNext = CTimer::GetTimeInMilliseconds();
 		if(i >= 14){
@@ -2659,8 +2659,8 @@ CCamera::ProcessObbeCinemaCameraPed(void)
 
 	if(!bDidWeProcessAnyCinemaCam || IsItTimeForNewcam(SequenceOfPedCams[PedOldMode], PedTimeForNext)){
 		for(PedOldMode = (PedOldMode+1) % 5;
-			!TryToStartNewCamMode(SequenceOfPedCams[PedOldMode]);
-			PedOldMode = (PedOldMode+1) % 5);
+		    !TryToStartNewCamMode(SequenceOfPedCams[PedOldMode]);
+		    PedOldMode = (PedOldMode+1) % 5);
 		PedTimeForNext = CTimer::GetTimeInMilliseconds();
 	}
 	bDidWeProcessAnyCinemaCam = true;
@@ -2813,11 +2813,11 @@ CCamera::Process_Train_Camera_Control(void)
 	uint32 node = m_iCurrentTrainCamNode;
 	for(i = 0; i < m_uiNumberOfTrainCamNodes && !found; i++){
 		if(target->IsWithinArea(m_arrTrainCamNode[node].m_cvecMinPointInRange.x,
-								m_arrTrainCamNode[node].m_cvecMinPointInRange.y,
-								m_arrTrainCamNode[node].m_cvecMinPointInRange.z,
-								m_arrTrainCamNode[node].m_cvecMaxPointInRange.x,
-								m_arrTrainCamNode[node].m_cvecMaxPointInRange.y,
-								m_arrTrainCamNode[node].m_cvecMaxPointInRange.z)){
+		                        m_arrTrainCamNode[node].m_cvecMinPointInRange.y,
+		                        m_arrTrainCamNode[node].m_cvecMinPointInRange.z,
+		                        m_arrTrainCamNode[node].m_cvecMaxPointInRange.x,
+		                        m_arrTrainCamNode[node].m_cvecMaxPointInRange.y,
+		                        m_arrTrainCamNode[node].m_cvecMaxPointInRange.z)){
 			m_iCurrentTrainCamNode = node;
 			found = true;
 		}

From 8e29a5ec884842e0c445b3fb00b359386b7dca3e Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Wed, 8 Apr 2020 14:06:27 +0300
Subject: [PATCH 7/8] bug fix

---
 src/control/Garages.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 9e10af2d..84d49bee 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -1679,7 +1679,7 @@ float CGarage::CalcDistToGarageRectangleSquared(float X, float Y)
 	else
 		distX = 0.0f;
 	if (Y < m_fY1)
-		distY = m_fY1 - X;
+		distY = m_fY1 - Y;
 	else if (Y > m_fY2)
 		distY = Y - m_fY2;
 	else
@@ -2358,4 +2358,4 @@ STARTPATCHES
 	InjectHook(0x427AB0, CGarages::IsPointInAGarageCameraZone, PATCH_JUMP); // CCamera::CamControl
 	InjectHook(0x427BC0, CGarages::CameraShouldBeOutside, PATCH_JUMP); // CCamera::CamControl
 	InjectHook(0x428940, CGarages::Load, PATCH_JUMP); // GenericLoad
-ENDPATCHES
\ No newline at end of file
+ENDPATCHES

From 8ee98574ffa61abf1d14e9511056dcadd537fc8b Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Wed, 8 Apr 2020 14:16:59 +0300
Subject: [PATCH 8/8] fix bug

---
 src/control/Script.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 6b79265a..db36d766 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -7117,7 +7117,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command)
 	case COMMAND_CLOSE_GARAGE:
 	{
 		CollectParameters(&m_nIp, 1);
-		CGarages::CloseGarage(ScriptParams[1]);
+		CGarages::CloseGarage(ScriptParams[0]);
 		return 0;
 	}
 	case COMMAND_WARP_CHAR_FROM_CAR_TO_COORD: