diff --git a/src/audio/AudioScriptObject.cpp b/src/audio/AudioScriptObject.cpp
index c5115ddb..796cd88b 100644
--- a/src/audio/AudioScriptObject.cpp
+++ b/src/audio/AudioScriptObject.cpp
@@ -3,6 +3,8 @@
 #include "AudioScriptObject.h"
 #include "Pools.h"
 
+WRAPPER void cAudioScriptObject::SaveAllAudioScriptObjects(uint8 *buf, uint32 *size) { EAXJMP(0x57c460); }
+
 void
 cAudioScriptObject::Reset()
 {
diff --git a/src/audio/AudioScriptObject.h b/src/audio/AudioScriptObject.h
index 9aac1c30..1db19865 100644
--- a/src/audio/AudioScriptObject.h
+++ b/src/audio/AudioScriptObject.h
@@ -141,6 +141,8 @@ public:
 	static void* operator new(size_t, int);
 	static void operator delete(void*, size_t);
 	static void operator delete(void*, int);
+
+	static void SaveAllAudioScriptObjects(uint8 *buf, uint32 *size);
 };
 
 static_assert(sizeof(cAudioScriptObject) == 20, "cAudioScriptObject: error");
diff --git a/src/control/Cranes.cpp b/src/control/Cranes.cpp
index c8d64077..4c1bf2c8 100644
--- a/src/control/Cranes.cpp
+++ b/src/control/Cranes.cpp
@@ -9,4 +9,6 @@ WRAPPER bool CCranes::HaveAllCarsBeenCollectedByMilitaryCrane() { EAXJMP(0x544BE
 WRAPPER void CCranes::ActivateCrane(float, float, float, float, float, float, float, float, bool, bool, float, float) { EAXJMP(0x543650); }
 WRAPPER void CCranes::DeActivateCrane(float, float) { EAXJMP(0x543890); }
 WRAPPER void CCranes::InitCranes(void) { EAXJMP(0x543360); }
-WRAPPER void CCranes::UpdateCranes(void) { EAXJMP(0x5439E0); }
\ No newline at end of file
+WRAPPER void CCranes::UpdateCranes(void) { EAXJMP(0x5439E0); }
+WRAPPER void CCranes::Save(uint8*, uint32*) { EAXJMP(0x545210); }
+WRAPPER void CranesLoad(uint8*, uint32) { EAXJMP(0x5454d0); }
diff --git a/src/control/Cranes.h b/src/control/Cranes.h
index 4625463e..9f606c9f 100644
--- a/src/control/Cranes.h
+++ b/src/control/Cranes.h
@@ -14,4 +14,7 @@ public:
 	static void DeActivateCrane(float, float);
 	static void InitCranes(void);
 	static void UpdateCranes(void);
+	static void Save(uint8*, uint32*);
 };
+
+void CranesLoad(uint8*, uint32);	// is this really outside CCranes?
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 8270780d..9f300257 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -31,6 +31,8 @@ CGarage(&CGarages::Garages)[NUM_GARAGES] = *(CGarage(*)[NUM_GARAGES])(uintptr*)0
 
 WRAPPER void CGarages::Init(void) { EAXJMP(0x421C60); }
 WRAPPER void CGarages::Update(void) { EAXJMP(0x421E40); }
+WRAPPER void CGarages::Load(uint8* buf, uint32 size) { EAXJMP(0x428940); }
+WRAPPER void CGarages::Save(uint8* buf, uint32 *size) { EAXJMP(0x4284e0); }
 
 bool
 CGarages::IsModelIndexADoor(uint32 id)
diff --git a/src/control/Garages.h b/src/control/Garages.h
index fe0d1a20..5e106ade 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -147,6 +147,8 @@ public:
 	static void PlayerArrestedOrDied();
 	static void Init(void);
 	static void Update(void);
+	static void Load(uint8 *buf, uint32 size);
+	static void Save(uint8 *buf, uint32 *size);
 	static int16 AddOne(float, float, float, float, float, float, uint8, uint32);
 	static void SetTargetCarForMissonGarage(int16, CVehicle*);
 	static bool HasCarBeenDroppedOffYet(int16);
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 495c3840..4734cd51 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -56,8 +56,8 @@ CReference *&CReplay::pEmptyReferences = *(CReference**)0x8F256C;
 CStoredDetailedAnimationState *&CReplay::pPedAnims = *(CStoredDetailedAnimationState**)0x8F6260;
 uint8 *&CReplay::pPickups = *(uint8**)0x8F1A48;
 uint8 *&CReplay::pReferences = *(uint8**)0x880FAC;
-uint8(&CReplay::BufferStatus)[8] = *(uint8(*)[8])*(uintptr*)0x8804D8;
-uint8(&CReplay::Buffers)[8][100000] = *(uint8(*)[8][100000])*(uintptr*)0x779958;
+uint8(&CReplay::BufferStatus)[NUM_REPLAYBUFFERS] = *(uint8(*)[NUM_REPLAYBUFFERS])*(uintptr*)0x8804D8;
+uint8(&CReplay::Buffers)[NUM_REPLAYBUFFERS][REPLAYBUFFERSIZE] = *(uint8(*)[NUM_REPLAYBUFFERS][REPLAYBUFFERSIZE])*(uintptr*)0x779958;
 bool &CReplay::bPlayingBackFromFile = *(bool*)0x95CD58;
 bool &CReplay::bReplayEnabled = *(bool*)0x617CAC;
 uint32 &CReplay::SlowMotion = *(uint32*)0x9414D4;
@@ -201,7 +201,7 @@ void CReplay::Init(void)
 	Record.m_nOffset = 0;
 	Record.m_pBase = nil;
 	Record.m_bSlot = 0;
-	for (int i = 0; i < 8; i++)
+	for (int i = 0; i < NUM_REPLAYBUFFERS; i++)
 		BufferStatus[i] = REPLAYBUFFER_UNUSED;
 	Record.m_bSlot = 0;
 	Record.m_pBase = Buffers[0];
@@ -250,6 +250,10 @@ void CReplay::Update(void)
 			SaveReplayToHD();
 		if (CPad::GetPad(0)->GetFJustDown(2))
 			PlayReplayFromHD();
+#ifdef USE_BETA_REPLAY_MODE
+		if (CPad::GetPad(0)->GetFJustDown(3))
+			TriggerPlaybackLastCoupleOfSeconds(5000, REPLAYCAMMODE_TOPDOWN, 0.0f, 0.0f, 0.0f, 4);
+#endif
 	}
 }
 
@@ -258,6 +262,41 @@ WRAPPER void CReplay::RecordThisFrame(void) { EAXJMP(0x5932B0); }
 #else
 void CReplay::RecordThisFrame(void)
 {
+#ifdef FIX_REPLAY_BUGS
+	uint32 memory_required = sizeof(tGeneralPacket) + sizeof(tClockPacket) + sizeof(tWeatherPacket) + sizeof(tTimerPacket);
+	CVehiclePool* vehiclesT = CPools::GetVehiclePool();
+	for (int i = 0; i < vehiclesT->GetSize(); i++) {
+		CVehicle* v = vehiclesT->GetSlot(i);
+		if (v && v->m_rwObject && v->GetModelIndex() != MI_AIRTRAIN && v->GetModelIndex() != MI_TRAIN)
+			memory_required += sizeof(tVehicleUpdatePacket);
+	}
+	CPedPool* pedsT = CPools::GetPedPool();
+	for (int i = 0; i < pedsT->GetSize(); i++) {
+		CPed* p = pedsT->GetSlot(i);
+		if (!p || !p->m_rwObject)
+			continue;
+		if (!p->bHasAlreadyBeenRecorded) {
+			memory_required += sizeof(tPedHeaderPacket);
+		}
+		memory_required += sizeof(tPedUpdatePacket);
+	}
+	for (uint8 i = 0; i < 16; i++) {
+		if (!CBulletTraces::aTraces[i].m_bInUse)
+			continue;
+		memory_required += sizeof(tBulletTracePacket);
+	}
+	memory_required += sizeof(tEndOfFramePacket);
+	if (Record.m_nOffset + memory_required > REPLAYBUFFERSIZE) {
+		Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
+		BufferStatus[Record.m_bSlot] = REPLAYBUFFER_PLAYBACK;
+		Record.m_bSlot = (Record.m_bSlot + 1) % NUM_REPLAYBUFFERS;
+		BufferStatus[Record.m_bSlot] = REPLAYBUFFER_RECORD;
+		Record.m_pBase = Buffers[Record.m_bSlot];
+		Record.m_nOffset = 0;
+		*Record.m_pBase = REPLAYPACKET_END;
+		MarkEverythingAsNew();
+	}
+#endif
 	tGeneralPacket* general = (tGeneralPacket*)&Record.m_pBase[Record.m_nOffset];
 	general->type = REPLAYPACKET_GENERAL;
 	general->camera_pos.CopyOnlyMatrix(&TheCamera.GetMatrix());
@@ -316,21 +355,22 @@ void CReplay::RecordThisFrame(void)
 	tEndOfFramePacket* eof = (tEndOfFramePacket*)&Record.m_pBase[Record.m_nOffset];
 	eof->type = REPLAYPACKET_ENDOFFRAME;
 	Record.m_nOffset += sizeof(*eof);
-	if (Record.m_nOffset <= 97000){
+	Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
+#ifndef FIX_REPLAY_BUGS
+	if (Record.m_nOffset <= REPLAYBUFFERSIZE - 3000){
 		/* Unsafe assumption which can cause buffer overflow
 		 * if size of next frame exceeds 3000 bytes.
 		 * Most notably it causes various timecyc errors. */
-		Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
 		return;
 	}
-	Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
 	BufferStatus[Record.m_bSlot] = REPLAYBUFFER_PLAYBACK;
-	Record.m_bSlot = (Record.m_bSlot + 1) % 8;
+	Record.m_bSlot = (Record.m_bSlot + 1) % NUM_REPLAYBUFFERS;
 	BufferStatus[Record.m_bSlot] = REPLAYBUFFER_RECORD;
 	Record.m_pBase = Buffers[Record.m_bSlot];
 	Record.m_nOffset = 0;
 	*Record.m_pBase = REPLAYPACKET_END;
 	MarkEverythingAsNew();
+#endif
 }
 #endif
 
@@ -366,8 +406,8 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
 	CAnimBlendAssociation* main = RpAnimBlendClumpGetMainAssociation((RpClump*)ped->m_rwObject, &second, &blend_amount);
 	if (main){
 		state->animId = main->animId;
-		state->time = 255.0f / 4.0f * max(0.0f, min(4.0f, main->currentTime));
-		state->speed = 255.0f / 3.0f * max(0.0f, min(3.0f, main->speed));
+		state->time = 255.0f / 4.0f * clamp(main->currentTime, 0.0f, 4.0f);
+		state->speed = 255.0f / 3.0f * clamp(main->speed, 0.0f, 3.0f);
 	}else{
 		state->animId = 3;
 		state->time = 0;
@@ -375,9 +415,9 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
 	}
 	if (second) {
 		state->secAnimId = second->animId;
-		state->secTime = 255.0f / 4.0f * max(0.0f, min(4.0f, second->currentTime));
-		state->secSpeed = 255.0f / 3.0f * max(0.0f, min(3.0f, second->speed));
-		state->blendAmount = 255.0f / 2.0f * max(0.0f, min(2.0f, blend_amount));
+		state->secTime = 255.0f / 4.0f * clamp(second->currentTime, 0.0f, 4.0f);
+		state->secSpeed = 255.0f / 3.0f * clamp(second->speed, 0.0f, 3.0f);
+		state->blendAmount = 255.0f / 2.0f * clamp(blend_amount, 0.0f, 2.0f);
 	}else{
 		state->secAnimId = 0;
 		state->secTime = 0;
@@ -387,9 +427,9 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
 	CAnimBlendAssociation* partial = RpAnimBlendClumpGetMainPartialAssociation((RpClump*)ped->m_rwObject);
 	if (partial) {
 		state->partAnimId = partial->animId;
-		state->partAnimTime = 255.0f / 4.0f * max(0.0f, min(4.0f, partial->currentTime));
-		state->partAnimSpeed = 255.0f / 3.0f * max(0.0f, min(3.0f, partial->speed));
-		state->partBlendAmount = 255.0f / 2.0f * max(0.0f, min(2.0f, partial->blendAmount));
+		state->partAnimTime = 255.0f / 4.0f * clamp(partial->currentTime, 0.0f, 4.0f);
+		state->partAnimSpeed = 255.0f / 3.0f * clamp(partial->speed, 0.0f, 3.0f);
+		state->partBlendAmount = 255.0f / 2.0f * clamp(partial->blendAmount, 0.0f, 2.0f);
 	}else{
 		state->partAnimId = 0;
 		state->partAnimTime = 0;
@@ -404,13 +444,16 @@ WRAPPER void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimat
 #else
 void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state)
 {
-	for (int i = 0; i < 3; i++){
+	for (int i = 0; i < NUM_MAIN_ANIMS_IN_REPLAY; i++){
 		CAnimBlendAssociation* assoc = RpAnimBlendClumpGetMainAssociation_N((RpClump*)ped->m_rwObject, i);
 		if (assoc){
 			state->aAnimId[i] = assoc->animId;
-			state->aCurTime[i] = 255.0f / 4.0f * max(0.0f, min(4.0f, assoc->currentTime));
-			state->aSpeed[i] = 255.0f / 3.0f * max(0.0f, min(3.0f, assoc->speed));
-			state->aBlendAmount[i] = 255.0f / 2.0f * max(0.0f, min(2.0f, assoc->blendAmount));
+			state->aCurTime[i] = 255.0f / 4.0f * clamp(assoc->currentTime, 0.0f, 4.0f);
+			state->aSpeed[i] = 255.0f / 3.0f * clamp(assoc->speed, 0.0f, 3.0f);
+			state->aBlendAmount[i] = 255.0f / 2.0f * clamp(assoc->blendAmount, 0.0f, 2.0f);
+#ifdef FIX_REPLAY_BUGS
+			state->aBlendDelta[i] = 127.0f / 32.0f * clamp(assoc->blendDelta, -16.0f, 16.0f);
+#endif
 			state->aFlags[i] = assoc->flags;
 			if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH || assoc->callbackType == CAnimBlendAssociation::CB_DELETE) {
 				state->aFunctionCallbackID[i] = FindCBFunctionID(assoc->callback);
@@ -427,13 +470,16 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
 			state->aFlags[i] = 0;
 		}
 	}
-	for (int i = 0; i < 6; i++) {
+	for (int i = 0; i < NUM_PARTIAL_ANIMS_IN_REPLAY; i++) {
 		CAnimBlendAssociation* assoc = RpAnimBlendClumpGetMainPartialAssociation_N((RpClump*)ped->m_rwObject, i);
 		if (assoc) {
 			state->aAnimId2[i] = assoc->animId;
-			state->aCurTime2[i] = 255.0f / 4.0f * max(0.0f, min(4.0f, assoc->currentTime));
-			state->aSpeed2[i] = 255.0f / 3.0f * max(0.0f, min(3.0f, assoc->speed));
-			state->aBlendAmount2[i] = 255.0f / 2.0f * max(0.0f, min(2.0f, assoc->blendAmount));
+			state->aCurTime2[i] = 255.0f / 4.0f * clamp(assoc->currentTime, 0.0f, 4.0f);
+			state->aSpeed2[i] = 255.0f / 3.0f * clamp(assoc->speed, 0.0f, 3.0f);
+			state->aBlendAmount2[i] = 255.0f / 2.0f * clamp(assoc->blendAmount, 0.0f, 2.0f);
+#ifdef FIX_REPLAY_BUGS
+			state->aBlendDelta2[i] = 127.0f / 16.0f * clamp(assoc->blendDelta, -16.0f, 16.0f);
+#endif
 			state->aFlags2[i] = assoc->flags;
 			if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH || assoc->callbackType == CAnimBlendAssociation::CB_DELETE) {
 				state->aFunctionCallbackID2[i] = FindCBFunctionID(assoc->callback);
@@ -460,7 +506,7 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB
 {
 	tPedUpdatePacket *pp = (tPedUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset];
 	if (!ped){
-		debug("Replay:Ped wasn't there\n");
+		printf("Replay:Ped wasn't there\n");
 		buffer->m_nOffset += sizeof(tPedUpdatePacket);
 		return;
 	}
@@ -541,17 +587,33 @@ WRAPPER void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAni
 #else
 void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state)
 {
-	for (int i = 0; i < 3; i++){
+#ifdef FIX_REPLAY_BUGS
+	CAnimBlendAssociation* assoc;
+	for (int i = 0; ((assoc = RpAnimBlendClumpGetMainAssociation_N(ped->GetClump(), i))); i++)
+		assoc->SetBlend(0.0f, -1.0f);
+	for (int i = 0; ((assoc = RpAnimBlendClumpGetMainPartialAssociation_N(ped->GetClump(), i))); i++)
+		assoc->SetBlend(0.0f, -1.0f);
+#endif
+	for (int i = 0; i < NUM_MAIN_ANIMS_IN_REPLAY; i++) {
 		if (state->aAnimId[i] == NUM_ANIMS)
 			continue;
+#ifdef FIX_REPLAY_BUGS
+		CAnimBlendAssociation* anim = CAnimManager::AddAnimation(ped->GetClump(),
+			state->aAnimId[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
+			(AnimationId)state->aAnimId[i]);
+#else
 		CAnimBlendAssociation* anim = CAnimManager::BlendAnimation(
 			(RpClump*)ped->m_rwObject,
 			state->aAnimId[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
 			(AnimationId)state->aAnimId[i], 100.0f);
+#endif
 		anim->SetCurrentTime(state->aCurTime[i] * 4.0f / 255.0f);
 		anim->speed = state->aSpeed[i] * 3.0f / 255.0f;
-		/* Lack of commented out calculation causes megajump */
-		anim->SetBlend(state->aBlendAmount[i] /* * 2.0f / 255.0f */, 1.0f);
+#ifdef FIX_REPLAY_BUGS
+		anim->SetBlend(state->aBlendAmount[i] * 2.0f / 255.0f, state->aBlendDelta[i] * 16.0f / 127.0f);
+#else
+		anim->SetBlend(state->aBlendAmount[i], 1.0f);
+#endif
 		anim->flags = state->aFlags[i];
 		uint8 callback = state->aFunctionCallbackID[i];
 		if (!callback)
@@ -561,17 +623,26 @@ void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationSt
 		else
 			anim->SetDeleteCallback(FindCBFunction(callback & 0x7F), ped);
 	}
-	for (int i = 0; i < 6; i++) {
+	for (int i = 0; i < NUM_PARTIAL_ANIMS_IN_REPLAY; i++) {
 		if (state->aAnimId2[i] == NUM_ANIMS)
 			continue;
+#ifdef FIX_REPLAY_BUGS
+		CAnimBlendAssociation* anim = CAnimManager::AddAnimation(ped->GetClump(),
+			state->aAnimId2[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
+			(AnimationId)state->aAnimId2[i]);
+#else
 		CAnimBlendAssociation* anim = CAnimManager::BlendAnimation(
 			(RpClump*)ped->m_rwObject,
 			state->aAnimId2[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
 			(AnimationId)state->aAnimId2[i], 100.0f);
+#endif
 		anim->SetCurrentTime(state->aCurTime2[i] * 4.0f / 255.0f);
 		anim->speed = state->aSpeed2[i] * 3.0f / 255.0f;
-		/* Lack of commented out calculation causes megajump */
-		anim->SetBlend(state->aBlendAmount2[i] /* * 2.0f / 255.0f */, 1.0f);
+#ifdef FIX_REPLAY_BUGS
+		anim->SetBlend(state->aBlendAmount2[i] * 2.0f / 255.0f, state->aBlendDelta2[i] * 16.0f / 127.0f);
+#else
+		anim->SetBlend(state->aBlendAmount2[i], 1.0f);
+#endif
 		anim->flags = state->aFlags2[i];
 		uint8 callback = state->aFunctionCallbackID2[i];
 		if (!callback)
@@ -589,23 +660,23 @@ WRAPPER void CReplay::PlaybackThisFrame(void) { EAXJMP(0x5946B0); }
 #else
 void CReplay::PlaybackThisFrame(void)
 {
-	static int SlowMotionCounter = 0;
+	static int FrameSloMo = 0;
 	CAddressInReplayBuffer buf = Playback;
 	if (PlayBackThisFrameInterpolation(&buf, 1.0f, nil)){
 		DMAudio.SetEffectsFadeVol(127);
 		DMAudio.SetMusicFadeVol(127);
 		return;
 	}
-	if (SlowMotionCounter){
+	if (FrameSloMo){
 		CAddressInReplayBuffer buf_sm = buf;
-		if (PlayBackThisFrameInterpolation(&buf_sm, SlowMotionCounter * 1.0f / SlowMotion, nil)){
+		if (PlayBackThisFrameInterpolation(&buf_sm, FrameSloMo * 1.0f / SlowMotion, nil)){
 			DMAudio.SetEffectsFadeVol(127);
 			DMAudio.SetMusicFadeVol(127);
 			return;
 		}
 	}
-	SlowMotionCounter = (SlowMotionCounter + 1) % SlowMotion;
-	if (SlowMotionCounter == 0)
+	FrameSloMo = (FrameSloMo + 1) % SlowMotion;
+	if (FrameSloMo == 0)
 		Playback = buf;
 	ProcessLookAroundCam();
 	DMAudio.SetEffectsFadeVol(0);
@@ -613,6 +684,29 @@ void CReplay::PlaybackThisFrame(void)
 }
 #endif
 
+// next two functions are only found in mobile version
+// most likely they were optimized out for being unused
+
+void CReplay::TriggerPlaybackLastCoupleOfSeconds(uint32 start, uint8 cam_mode, float cam_x, float cam_y, float cam_z, uint32 slomo)
+{
+	if (Mode != MODE_RECORD)
+		return;
+	TriggerPlayback(cam_mode, cam_x, cam_y, cam_z, true);
+	SlowMotion = slomo;
+	bAllowLookAroundCam = false;
+	if (!FastForwardToTime(CTimer::GetTimeInMilliseconds() - start))
+		Mode = MODE_RECORD;
+}
+
+bool CReplay::FastForwardToTime(uint32 start)
+{
+	uint32 timer = 0;
+	while (start > timer)
+		if (PlayBackThisFrameInterpolation(&Playback, 1.0f, &timer))
+			return false;
+	return true;
+}
+
 #if 0
 WRAPPER void CReplay::StoreCarUpdate(CVehicle *vehicle, int id) { EAXJMP(0x5947F0); }
 #else
@@ -660,7 +754,7 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI
 {
 	tVehicleUpdatePacket* vp = (tVehicleUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset];
 	if (!vehicle){
-		debug("Replay:Car wasn't there");
+		printf("Replay:Car wasn't there");
 		return;
 	}
 	CMatrix vehicle_matrix;
@@ -686,34 +780,34 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI
 			car->m_aSuspensionSpringRatio[i] = vp->wheel_susp_dist[i] / 50.0f;
 			car->m_aWheelRotation[i] = vp->wheel_rotation[i] * PI / 128.0f;
 		}
-		car->Doors[2].m_fAngle = car->Doors[2].m_fPrevAngle = vp->door_angles[0] * PI / 127.0f;
-		car->Doors[3].m_fAngle = car->Doors[3].m_fPrevAngle = vp->door_angles[1] * PI / 127.0f;
+		car->Doors[DOOR_FRONT_LEFT].m_fAngle = car->Doors[DOOR_FRONT_LEFT].m_fPrevAngle = vp->door_angles[0] * PI / 127.0f;
+		car->Doors[DOOR_FRONT_RIGHT].m_fAngle = car->Doors[DOOR_FRONT_RIGHT].m_fPrevAngle = vp->door_angles[1] * PI / 127.0f;
 		if (vp->door_angles[0])
-			car->Damage.SetDoorStatus(2, 2);
+			car->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING);
 		if (vp->door_angles[1])
-			car->Damage.SetDoorStatus(3, 2);
+			car->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_SWINGING);
 		if (vp->door_status & 1 && car->Damage.GetDoorStatus(DOOR_BONNET) != 3){
-			car->Damage.SetDoorStatus(DOOR_BONNET, 3);
+			car->Damage.SetDoorStatus(DOOR_BONNET, DOOR_STATUS_MISSING);
 			car->SetDoorDamage(CAR_BONNET, DOOR_BONNET, true);
 		}
 		if (vp->door_status & 2 && car->Damage.GetDoorStatus(DOOR_BOOT) != 3) {
-			car->Damage.SetDoorStatus(DOOR_BOOT, 3);
+			car->Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_MISSING);
 			car->SetDoorDamage(CAR_BOOT, DOOR_BOOT, true);
 		}
 		if (vp->door_status & 4 && car->Damage.GetDoorStatus(DOOR_FRONT_LEFT) != 3) {
-			car->Damage.SetDoorStatus(DOOR_FRONT_LEFT, 3);
+			car->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING);
 			car->SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT, true);
 		}
 		if (vp->door_status & 8 && car->Damage.GetDoorStatus(DOOR_FRONT_RIGHT) != 3) {
-			car->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, 3);
+			car->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING);
 			car->SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT, true);
 		}
 		if (vp->door_status & 0x10 && car->Damage.GetDoorStatus(DOOR_REAR_LEFT) != 3) {
-			car->Damage.SetDoorStatus(DOOR_REAR_LEFT, 3);
+			car->Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING);
 			car->SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT, true);
 		}
 		if (vp->door_status & 0x20 && car->Damage.GetDoorStatus(DOOR_REAR_RIGHT) != 3) {
-			car->Damage.SetDoorStatus(DOOR_REAR_RIGHT, 3);
+			car->Damage.SetDoorStatus(DOOR_REAR_RIGHT, DOOR_STATUS_MISSING);
 			car->SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT, true);
 		}
 		vehicle->bEngineOn = true;
@@ -738,7 +832,9 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
 	 * Obviously fact of picking them up is a bug on its own,
 	 * but it doesn't cancel this one.
 	 */
+#ifndef FIX_REPLAY_BUGS
 	FindPlayerPed()->m_pWanted = &PlayerWanted;
+#endif
 
 	CBulletTraces::Init();
 	float split = 1.0f - interpolation;
@@ -758,7 +854,7 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
 				FinishPlayback();
 				return true;
 			}
-			buffer->m_bSlot = (slot + 1) % 8;
+			buffer->m_bSlot = (slot + 1) % NUM_REPLAYBUFFERS;
 			buffer->m_nOffset = 0;
 			buffer->m_pBase = Buffers[buffer->m_bSlot];
 			ped_min_index = 0;
@@ -880,6 +976,7 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
 		case REPLAYPACKET_ENDOFFRAME:
 		{
 			/* Not supposed to be here. */
+			assert(false);
 			buffer->m_nOffset++;
 			break;
 		}
@@ -961,7 +1058,7 @@ void CReplay::EmptyReplayBuffer(void)
 	if (Mode == MODE_PLAYBACK)
 		return;
 	Record.m_nOffset = 0;
-	for (int i = 0; i < 8; i++){
+	for (int i = 0; i < NUM_REPLAYBUFFERS; i++){
 		BufferStatus[i] = REPLAYBUFFER_UNUSED;
 	}
 	Record.m_bSlot = 0;
@@ -1040,11 +1137,11 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca
 	DMAudio.SetEffectsFadeVol(0);
 	DMAudio.SetMusicFadeVol(0);
 	int current;
-	for (current = 0; current < 8; current++)
+	for (current = 0; current < NUM_REPLAYBUFFERS; current++)
 		if (BufferStatus[current] == REPLAYBUFFER_RECORD)
 			break;
 	int first;
-	for (first = (current + 1) % 8; ; first = (first + 1) % 8)
+	for (first = (current + 1) % NUM_REPLAYBUFFERS; ; first = (first + 1) % NUM_REPLAYBUFFERS)
 		if (BufferStatus[first] == REPLAYBUFFER_RECORD || BufferStatus[first] == REPLAYBUFFER_PLAYBACK)
 			break;
 	Playback.m_bSlot = first;
@@ -1153,7 +1250,11 @@ void CReplay::RestoreStuffFromMem(void)
 	memcpy(CRadar::ms_RadarTrace, pRadarBlips, sizeof(CBlip) * NUMRADARBLIPS);
 	delete[] pRadarBlips;
 	pRadarBlips = nil;
-	FindPlayerPed()->m_pWanted = new CWanted(PlayerWanted); /* Nice memory leak */
+#ifdef FIX_REPLAY_BUGS
+	// NB: can only be used with fixed bug at the start of PlayBackThisFrameInterpolation
+	delete FindPlayerPed()->m_pWanted;
+#endif
+	FindPlayerPed()->m_pWanted = new CWanted(PlayerWanted);
 	CWorld::Players[0] = PlayerInfo;
 	int i = CPools::GetPedPool()->GetSize();
 	while (--i >= 0) {
@@ -1366,25 +1467,25 @@ void CReplay::SaveReplayToHD(void)
 {
 	CFileMgr::SetDirMyDocuments();
 	int fw = CFileMgr::OpenFileForWriting("replay.rep");
-#ifdef FIX_BUGS
+#ifdef FIX_REPLAY_BUGS
 	if (fw == 0) {
 #else
 	if (fw < 0){ // BUG?
 #endif
-		debug("Couldn't open replay.rep for writing");
+		printf("Couldn't open replay.rep for writing");
 		CFileMgr::SetDir("");
 		return;
 	}
 	CFileMgr::Write(fw, "gta3_7f", sizeof("gta3_7f"));
 	int current;
-	for (current = 0; current < 8; current++)
+	for (current = 0; current < NUM_REPLAYBUFFERS; current++)
 		if (BufferStatus[current] == REPLAYBUFFER_RECORD)
 			break;
 	int first;
-	for (first = (current + 1) % 8; ; first = (first + 1) % 8)
+	for (first = (current + 1) % NUM_REPLAYBUFFERS; ; first = (first + 1) % NUM_REPLAYBUFFERS)
 		if (BufferStatus[first] == REPLAYBUFFER_RECORD || BufferStatus[first] == REPLAYBUFFER_PLAYBACK)
 			break;
-	for(int i = first;; i = (i + 1) % 8 ){
+	for(int i = first;; i = (i + 1) % NUM_REPLAYBUFFERS){
 		CFileMgr::Write(fw, (char*)Buffers[first], sizeof(Buffers[first]));
 		if (BufferStatus[i] == REPLAYBUFFER_RECORD)
 			break;
@@ -1402,14 +1503,16 @@ void PlayReplayFromHD(void)
 	CFileMgr::SetDirMyDocuments();
 	int fr = CFileMgr::OpenFile("replay.rep", "rb");
 	if (fr == 0) {
-		debug("Couldn't open replay.rep for reading");
-		/* Forgot to SetDir? */
+		printf("Couldn't open replay.rep for reading");
+#ifdef FIX_REPLAY_BUGS
+	CFileMgr::SetDir("");
+#endif
 		return;
 	}
 	CFileMgr::Read(fr, gString, 8);
 	if (strncmp(gString, "gta3_7f", sizeof("gta3_7f"))){
 		CFileMgr::CloseFile(fr);
-		debug("Wrong file type for replay");
+		printf("Wrong file type for replay");
 		CFileMgr::SetDir("");
 		return;
 	}
@@ -1417,7 +1520,7 @@ void PlayReplayFromHD(void)
 	for (slot = 0; CFileMgr::Read(fr, (char*)CReplay::Buffers[slot], sizeof(CReplay::Buffers[slot])); slot++)
 		CReplay::BufferStatus[slot] = CReplay::REPLAYBUFFER_PLAYBACK;
 	CReplay::BufferStatus[slot - 1] = CReplay::REPLAYBUFFER_RECORD;
-	while (slot < 8)
+	while (slot < CReplay::NUM_REPLAYBUFFERS)
 		CReplay::BufferStatus[slot++] = CReplay::REPLAYBUFFER_UNUSED;
 	CFileMgr::CloseFile(fr);
 	CFileMgr::SetDir("");
@@ -1433,7 +1536,7 @@ WRAPPER void CReplay::StreamAllNecessaryCarsAndPeds(void) { EAXJMP(0x597560); }
 #else
 void CReplay::StreamAllNecessaryCarsAndPeds(void)
 {
-	for (int slot = 0; slot < 8; slot++) {
+	for (int slot = 0; slot < NUM_REPLAYBUFFERS; slot++) {
 		if (BufferStatus[slot] == REPLAYBUFFER_UNUSED)
 			continue;
 		for (int offset = 0; Buffers[slot][offset] != REPLAYPACKET_END; offset += FindSizeOfPacket(Buffers[slot][offset])) {
@@ -1459,7 +1562,7 @@ WRAPPER void CReplay::FindFirstFocusCoordinate(CVector *coord) { EAXJMP(0x5975E0
 void CReplay::FindFirstFocusCoordinate(CVector *coord)
 {
 	*coord = CVector(0.0f, 0.0f, 0.0f);
-	for (int slot = 0; slot < 8; slot++) {
+	for (int slot = 0; slot < NUM_REPLAYBUFFERS; slot++) {
 		if (BufferStatus[slot] == REPLAYBUFFER_UNUSED)
 			continue;
 		for (int offset = 0; Buffers[slot][offset] != REPLAYPACKET_END; offset += FindSizeOfPacket(Buffers[slot][offset])) {
@@ -1561,7 +1664,7 @@ size_t CReplay::FindSizeOfPacket(uint8 type)
 	case REPLAYPACKET_ENDOFFRAME:	return 4;
 	case REPLAYPACKET_TIMER:		return sizeof(tTimerPacket);
 	case REPLAYPACKET_BULLET_TRACES:return sizeof(tBulletTracePacket);
-	default: break;
+	default: assert(false); break;
 	}
 	return 0;
 }
@@ -1572,11 +1675,11 @@ WRAPPER void CReplay::Display(void) { EAXJMP(0x595EE0); }
 #else
 void CReplay::Display()
 {
-	static int counter = 0;
+	static int TimeCount = 0;
 	if (Mode == MODE_RECORD)
 		return;
-	counter = (counter + 1) % 65536;
-	if ((counter & 0x20) == 0)
+	TimeCount = (TimeCount + 1) % UINT16_MAX;
+	if ((TimeCount & 0x20) == 0)
 		return;
 	CFont::SetPropOn();
 	CFont::SetBackgroundOff();
diff --git a/src/control/Replay.h b/src/control/Replay.h
index 6b11da75..cc652a11 100644
--- a/src/control/Replay.h
+++ b/src/control/Replay.h
@@ -10,6 +10,12 @@
 #include "World.h"
 #include "common.h"
 
+#ifdef FIX_BUGS
+#ifndef DONT_FIX_REPLAY_BUGS
+#define FIX_REPLAY_BUGS
+#endif
+#endif
+
 struct CAddressInReplayBuffer
 {
 	uint32 m_nOffset;
@@ -32,20 +38,31 @@ struct CStoredAnimationState
 	uint8 partBlendAmount;
 };
 
+enum {
+	NUM_MAIN_ANIMS_IN_REPLAY = 3,
+	NUM_PARTIAL_ANIMS_IN_REPLAY = 6
+};
+
 struct CStoredDetailedAnimationState
 {
-	uint8 aAnimId[3];
-	uint8 aCurTime[3];
-	uint8 aSpeed[3];
-	uint8 aBlendAmount[3];
-	uint8 aFunctionCallbackID[3];
-	uint16 aFlags[3];
-	uint8 aAnimId2[6];
-	uint8 aCurTime2[6];
-	uint8 aSpeed2[6];
-	uint8 aBlendAmount2[6];
-	uint8 aFunctionCallbackID2[6];
-	uint16 aFlags2[6];
+	uint8 aAnimId[NUM_MAIN_ANIMS_IN_REPLAY];
+	uint8 aCurTime[NUM_MAIN_ANIMS_IN_REPLAY];
+	uint8 aSpeed[NUM_MAIN_ANIMS_IN_REPLAY];
+	uint8 aBlendAmount[NUM_MAIN_ANIMS_IN_REPLAY];
+#ifdef FIX_REPLAY_BUGS
+	int8 aBlendDelta[NUM_MAIN_ANIMS_IN_REPLAY];
+#endif
+	uint8 aFunctionCallbackID[NUM_MAIN_ANIMS_IN_REPLAY];
+	uint16 aFlags[NUM_MAIN_ANIMS_IN_REPLAY];
+	uint8 aAnimId2[NUM_PARTIAL_ANIMS_IN_REPLAY];
+	uint8 aCurTime2[NUM_PARTIAL_ANIMS_IN_REPLAY];
+	uint8 aSpeed2[NUM_PARTIAL_ANIMS_IN_REPLAY];
+	uint8 aBlendAmount2[NUM_PARTIAL_ANIMS_IN_REPLAY];
+#ifdef FIX_REPLAY_BUGS
+	int8 aBlendDelta2[NUM_PARTIAL_ANIMS_IN_REPLAY];
+#endif
+	uint8 aFunctionCallbackID2[NUM_PARTIAL_ANIMS_IN_REPLAY];
+	uint16 aFlags2[NUM_PARTIAL_ANIMS_IN_REPLAY];
 };
 
 void PlayReplayFromHD(void);
@@ -82,6 +99,11 @@ class CReplay
 		REPLAYBUFFER_RECORD = 2
 	};
 
+	enum {
+		NUM_REPLAYBUFFERS = 8,
+		REPLAYBUFFERSIZE = 100000
+	};
+
 
 	struct tGeneralPacket
 	{
@@ -209,8 +231,8 @@ private:
 	static CStoredDetailedAnimationState *&pPedAnims;
 	static uint8 *&pPickups;
 	static uint8 *&pReferences;
-	static uint8 (&BufferStatus)[8];
-	static uint8 (&Buffers)[8][100000];
+	static uint8 (&BufferStatus)[NUM_REPLAYBUFFERS];
+	static uint8 (&Buffers)[NUM_REPLAYBUFFERS][REPLAYBUFFERSIZE];
 	static bool &bPlayingBackFromFile;
 	static bool &bReplayEnabled;
 	static uint32 &SlowMotion;
@@ -274,6 +296,8 @@ private:
 	static void RetrievePedAnimation(CPed *ped, CStoredAnimationState *state);
 	static void RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state);
 	static void PlaybackThisFrame(void);
+	static void TriggerPlaybackLastCoupleOfSeconds(uint32, uint8, float, float, float, uint32);
+	static bool FastForwardToTime(uint32);
 	static void StoreCarUpdate(CVehicle *vehicle, int id);
 	static void ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer);
 	static bool PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer);
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 4a6b5376..75c594cf 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -8106,6 +8106,8 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
 			if (model != -1)
 				break;
 			model = CStreaming::ms_vehiclesLoaded[index];
+			if (model == -1)
+				continue;
 			// desperatly want to believe this was inlined :|
 			CBaseModelInfo* pInfo = CModelInfo::GetModelInfo(model);
 			assert(pInfo->m_type == MITYPE_VEHICLE);
diff --git a/src/core/Clock.h b/src/core/Clock.h
index ea4263bd..6b9908ba 100644
--- a/src/core/Clock.h
+++ b/src/core/Clock.h
@@ -2,6 +2,7 @@
 
 class CClock
 {
+public:
 	static uint8  &ms_nGameClockHours;
 	static uint8  &ms_nGameClockMinutes;
 	static uint16 &ms_nGameClockSeconds;
@@ -11,7 +12,6 @@ class CClock
 	static uint32 &ms_nMillisecondsPerGameMinute;
 	static uint32 &ms_nLastClockTick;
 	static bool   &ms_bClockHasBeenStored;
-public:
 
 	static void Initialise(uint32 scale);
 	static void Update(void);
diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp
index 8e66b049..75536b88 100644
--- a/src/core/Pools.cpp
+++ b/src/core/Pools.cpp
@@ -14,6 +14,13 @@ CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28;
 CDummyPool *&CPools::ms_pDummyPool = *(CDummyPool**)0x8F2C18;
 CAudioScriptObjectPool *&CPools::ms_pAudioScriptObjectPool = *(CAudioScriptObjectPool**)0x8F1B6C;
 
+WRAPPER void CPools::LoadObjectPool(uint8* buf, uint32 size) { EAXJMP(0x4a2550); }
+WRAPPER void CPools::LoadPedPool(uint8* buf, uint32 size) { EAXJMP(0x4a2b50); }
+WRAPPER void CPools::LoadVehiclePool(uint8* buf, uint32 size) { EAXJMP(0x4a1b40); }
+WRAPPER void CPools::SaveObjectPool(uint8* buf, uint32 *size) { EAXJMP(0x4a22d0); }
+WRAPPER void CPools::SavePedPool(uint8* buf, uint32 *size) { EAXJMP(0x4a29b0); }
+WRAPPER void CPools::SaveVehiclePool(uint8* buf, uint32 *size) { EAXJMP(0x4a2080); }
+
 void
 CPools::Initialise(void)
 {
@@ -30,16 +37,16 @@ CPools::Initialise(void)
 
 void
 CPools::ShutDown(void)
-{
-	debug("PtrNodes left %d\n", ms_pPtrNodePool->GetNoOfUsedSpaces());
-	debug("EntryInfoNodes left %d\n", ms_pEntryInfoNodePool->GetNoOfUsedSpaces());
-	debug("Peds left %d\n", ms_pPedPool->GetNoOfUsedSpaces());
-	debug("Vehicles left %d\n", ms_pVehiclePool->GetNoOfUsedSpaces());
-	debug("Buildings left %d\n", ms_pBuildingPool->GetNoOfUsedSpaces());
-	debug("Treadables left %d\n", ms_pTreadablePool->GetNoOfUsedSpaces());
-	debug("Objects left %d\n", ms_pObjectPool->GetNoOfUsedSpaces());
-	debug("Dummys left %d\n", ms_pDummyPool->GetNoOfUsedSpaces());
-	debug("AudioScriptObjects left %d\n", ms_pAudioScriptObjectPool->GetNoOfUsedSpaces());
+{
+	debug("PtrNodes left %d\n", ms_pPtrNodePool->GetNoOfUsedSpaces());
+	debug("EntryInfoNodes left %d\n", ms_pEntryInfoNodePool->GetNoOfUsedSpaces());
+	debug("Peds left %d\n", ms_pPedPool->GetNoOfUsedSpaces());
+	debug("Vehicles left %d\n", ms_pVehiclePool->GetNoOfUsedSpaces());
+	debug("Buildings left %d\n", ms_pBuildingPool->GetNoOfUsedSpaces());
+	debug("Treadables left %d\n", ms_pTreadablePool->GetNoOfUsedSpaces());
+	debug("Objects left %d\n", ms_pObjectPool->GetNoOfUsedSpaces());
+	debug("Dummys left %d\n", ms_pDummyPool->GetNoOfUsedSpaces());
+	debug("AudioScriptObjects left %d\n", ms_pAudioScriptObjectPool->GetNoOfUsedSpaces());
 	printf("Shutdown pool started\n");
 
 	delete ms_pPtrNodePool;
@@ -62,12 +69,12 @@ CVehicle *CPools::GetVehicle(int32 handle) { return ms_pVehiclePool->GetAt(handl
 int32 CPools::GetObjectRef(CObject *object) { return ms_pObjectPool->GetIndex(object); }
 CObject *CPools::GetObject(int32 handle) { return ms_pObjectPool->GetAt(handle); }
 
-void
-CPools::CheckPoolsEmpty()
-{
-	assert(ms_pPedPool->GetNoOfUsedSpaces() == 0);
-	assert(ms_pVehiclePool->GetNoOfUsedSpaces() == 0);
-	printf("pools have beem cleared \n");
+void
+CPools::CheckPoolsEmpty()
+{
+	assert(ms_pPedPool->GetNoOfUsedSpaces() == 0);
+	assert(ms_pVehiclePool->GetNoOfUsedSpaces() == 0);
+	printf("pools have been cleared\n");
 }
 
 
diff --git a/src/core/Pools.h b/src/core/Pools.h
index 862062ee..74b87585 100644
--- a/src/core/Pools.h
+++ b/src/core/Pools.h
@@ -52,4 +52,10 @@ public:
 	static CObject *GetObject(int32 handle);
 	static void CheckPoolsEmpty();
 	static void MakeSureSlotInObjectPoolIsEmpty(int32 slot);
+	static void LoadObjectPool(uint8 *buf, uint32 size);
+	static void LoadPedPool(uint8 *buf, uint32 size);
+	static void LoadVehiclePool(uint8 *buf, uint32 size);
+	static void SaveObjectPool(uint8 *buf, uint32 *size);
+	static void SavePedPool(uint8 *buf, uint32 *size);
+	static void SaveVehiclePool(uint8 *buf, uint32 *size);
 };
diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp
index 4744246d..6421520b 100644
--- a/src/core/Radar.cpp
+++ b/src/core/Radar.cpp
@@ -1,144 +1,144 @@
-#include "config.h"
-#include "common.h"
-#include "patcher.h"
-#include "RwHelper.h"
-#include "Radar.h"
-#include "Camera.h"
-#include "Hud.h"
-#include "World.h"
-#include "Frontend.h"
-#include "General.h"
-#include "Vehicle.h"
-#include "Pools.h"
-#include "Script.h"
-#include "TxdStore.h"
-#include "World.h"
-#include "Streaming.h"
-#include "SpecialFX.h"
-
-float &CRadar::m_radarRange = *(float*)0x8E281C;
-CBlip (&CRadar::ms_RadarTrace)[NUMRADARBLIPS] = *(CBlip(*)[NUMRADARBLIPS]) * (uintptr*)0x6ED5E0;
-CVector2D &vec2DRadarOrigin = *(CVector2D*)0x6299B8;
-int32 gRadarTxdIds[64];// = (int*)0x6299C0;
-
-CSprite2d CRadar::AsukaSprite;// = *(CSprite2d*)0x8F1A40;
-CSprite2d CRadar::BombSprite;// = (CSprite2d*)0x8F5FB4;
-CSprite2d CRadar::CatSprite;// = (CSprite2d*)0x885B24;
-CSprite2d CRadar::CentreSprite;// = (CSprite2d*)0x8F6268;
-CSprite2d CRadar::CopcarSprite;// = (CSprite2d*)0x8F1A2C;
-CSprite2d CRadar::DonSprite;// = (CSprite2d*)0x8F2BE0;
-CSprite2d CRadar::EightSprite;// = (CSprite2d*)0x8F2BCC;
-CSprite2d CRadar::ElSprite;// = (CSprite2d*)0x8F1B80;
-CSprite2d CRadar::IceSprite;// = (CSprite2d*)0x9415FC;
-CSprite2d CRadar::JoeySprite;// = (CSprite2d*)0x8F2C00;
-CSprite2d CRadar::KenjiSprite;// = (CSprite2d*)0x8F2C68;
-CSprite2d CRadar::LizSprite;// = (CSprite2d*)0x8F5830;
-CSprite2d CRadar::LuigiSprite;// = (CSprite2d*)0x8F1A3C;
-CSprite2d CRadar::NorthSprite;// = (CSprite2d*)0x8F6274;
-CSprite2d CRadar::RaySprite;// = (CSprite2d*)0x8E2A7C;
-CSprite2d CRadar::SalSprite;// = (CSprite2d*)0x8F29EC;
-CSprite2d CRadar::SaveSprite;// = (CSprite2d*)0x8F5F74;
-CSprite2d CRadar::SpraySprite;// = (CSprite2d*)0x94307C;
-CSprite2d CRadar::TonySprite;// = (CSprite2d*)0x885B58;
-CSprite2d CRadar::WeaponSprite;// = (CSprite2d*)0x941534;
-
-CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { 
-	nil,
-	&AsukaSprite,
-	&BombSprite,
-	&CatSprite,
-	&CentreSprite,
-	&CopcarSprite,
-	&DonSprite,
-	&EightSprite,
-	&ElSprite,
-	&IceSprite,
-	&JoeySprite,
-	&KenjiSprite,
-	&LizSprite,
-	&LuigiSprite,
-	&NorthSprite,
-	&RaySprite,
-	&SalSprite,
-	&SaveSprite,
-	&SpraySprite,
-	&TonySprite,
-	&WeaponSprite
-};
-
-#define RADAR_NUM_TILES (8)
-#define RADAR_TILE_SIZE (WORLD_SIZE_X / RADAR_NUM_TILES)
-static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square");
-
-#define RADAR_MIN_RANGE (120.0f)
-#define RADAR_MAX_RANGE (350.0f)
-#define RADAR_MIN_SPEED (0.3f)
-#define RADAR_MAX_SPEED (0.9f)
-
-#if 0
-WRAPPER void CRadar::CalculateBlipAlpha(float) { EAXJMP(0x4A4F90); }
-#else
-uint8 CRadar::CalculateBlipAlpha(float dist)
-{
-	if (dist <= 1.0f)
-		return 255;
-
-	if (dist <= 5.0f)
-		return (128.0f * ((dist - 1.0f) / 4.0f)) + ((1.0f - (dist - 1.0f) / 4.0f) * 255.0f);
-
-	return 128;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ChangeBlipBrightness(int32, int32) { EAXJMP(0x4A57A0); }
-#else
-void CRadar::ChangeBlipBrightness(int32 i, int32 bright)
-{
+#include "config.h"
+#include "common.h"
+#include "patcher.h"
+#include "RwHelper.h"
+#include "Radar.h"
+#include "Camera.h"
+#include "Hud.h"
+#include "World.h"
+#include "Frontend.h"
+#include "General.h"
+#include "Vehicle.h"
+#include "Pools.h"
+#include "Script.h"
+#include "TxdStore.h"
+#include "World.h"
+#include "Streaming.h"
+#include "SpecialFX.h"
+
+float &CRadar::m_radarRange = *(float*)0x8E281C;
+CBlip (&CRadar::ms_RadarTrace)[NUMRADARBLIPS] = *(CBlip(*)[NUMRADARBLIPS]) * (uintptr*)0x6ED5E0;
+CVector2D &vec2DRadarOrigin = *(CVector2D*)0x6299B8;
+int32 gRadarTxdIds[64];// = (int*)0x6299C0;
+
+CSprite2d CRadar::AsukaSprite;// = *(CSprite2d*)0x8F1A40;
+CSprite2d CRadar::BombSprite;// = (CSprite2d*)0x8F5FB4;
+CSprite2d CRadar::CatSprite;// = (CSprite2d*)0x885B24;
+CSprite2d CRadar::CentreSprite;// = (CSprite2d*)0x8F6268;
+CSprite2d CRadar::CopcarSprite;// = (CSprite2d*)0x8F1A2C;
+CSprite2d CRadar::DonSprite;// = (CSprite2d*)0x8F2BE0;
+CSprite2d CRadar::EightSprite;// = (CSprite2d*)0x8F2BCC;
+CSprite2d CRadar::ElSprite;// = (CSprite2d*)0x8F1B80;
+CSprite2d CRadar::IceSprite;// = (CSprite2d*)0x9415FC;
+CSprite2d CRadar::JoeySprite;// = (CSprite2d*)0x8F2C00;
+CSprite2d CRadar::KenjiSprite;// = (CSprite2d*)0x8F2C68;
+CSprite2d CRadar::LizSprite;// = (CSprite2d*)0x8F5830;
+CSprite2d CRadar::LuigiSprite;// = (CSprite2d*)0x8F1A3C;
+CSprite2d CRadar::NorthSprite;// = (CSprite2d*)0x8F6274;
+CSprite2d CRadar::RaySprite;// = (CSprite2d*)0x8E2A7C;
+CSprite2d CRadar::SalSprite;// = (CSprite2d*)0x8F29EC;
+CSprite2d CRadar::SaveSprite;// = (CSprite2d*)0x8F5F74;
+CSprite2d CRadar::SpraySprite;// = (CSprite2d*)0x94307C;
+CSprite2d CRadar::TonySprite;// = (CSprite2d*)0x885B58;
+CSprite2d CRadar::WeaponSprite;// = (CSprite2d*)0x941534;
+
+CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { 
+	nil,
+	&AsukaSprite,
+	&BombSprite,
+	&CatSprite,
+	&CentreSprite,
+	&CopcarSprite,
+	&DonSprite,
+	&EightSprite,
+	&ElSprite,
+	&IceSprite,
+	&JoeySprite,
+	&KenjiSprite,
+	&LizSprite,
+	&LuigiSprite,
+	&NorthSprite,
+	&RaySprite,
+	&SalSprite,
+	&SaveSprite,
+	&SpraySprite,
+	&TonySprite,
+	&WeaponSprite
+};
+
+#define RADAR_NUM_TILES (8)
+#define RADAR_TILE_SIZE (WORLD_SIZE_X / RADAR_NUM_TILES)
+static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square");
+
+#define RADAR_MIN_RANGE (120.0f)
+#define RADAR_MAX_RANGE (350.0f)
+#define RADAR_MIN_SPEED (0.3f)
+#define RADAR_MAX_SPEED (0.9f)
+
+#if 0
+WRAPPER void CRadar::CalculateBlipAlpha(float) { EAXJMP(0x4A4F90); }
+#else
+uint8 CRadar::CalculateBlipAlpha(float dist)
+{
+	if (dist <= 1.0f)
+		return 255;
+
+	if (dist <= 5.0f)
+		return (128.0f * ((dist - 1.0f) / 4.0f)) + ((1.0f - (dist - 1.0f) / 4.0f) * 255.0f);
+
+	return 128;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ChangeBlipBrightness(int32, int32) { EAXJMP(0x4A57A0); }
+#else
+void CRadar::ChangeBlipBrightness(int32 i, int32 bright)
+{
 	int index = GetActualBlipArrayIndex(i);
 	if (index != -1)
-		ms_RadarTrace[index].m_bDim = bright != 1;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ChangeBlipColour(int32, int32) { EAXJMP(0x4A5770); }
-#else
-void CRadar::ChangeBlipColour(int32 i, int32 color)
-{
+		ms_RadarTrace[index].m_bDim = bright != 1;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ChangeBlipColour(int32, int32) { EAXJMP(0x4A5770); }
+#else
+void CRadar::ChangeBlipColour(int32 i, int32 color)
+{
 	int index = GetActualBlipArrayIndex(i);
 	if (index != -1)
-		ms_RadarTrace[index].m_nColor = color;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ChangeBlipDisplay(int32, eBlipDisplay) { EAXJMP(0x4A5810); }
-#else
-void CRadar::ChangeBlipDisplay(int32 i, eBlipDisplay display)
-{
+		ms_RadarTrace[index].m_nColor = color;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ChangeBlipDisplay(int32, eBlipDisplay) { EAXJMP(0x4A5810); }
+#else
+void CRadar::ChangeBlipDisplay(int32 i, eBlipDisplay display)
+{
 	int index = GetActualBlipArrayIndex(i);
 	if (index != -1)
-		ms_RadarTrace[index].m_eBlipDisplay = display;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ChangeBlipScale(int32, int32) { EAXJMP(0x4A57E0); }
-#else
-void CRadar::ChangeBlipScale(int32 i, int32 scale)
-{
+		ms_RadarTrace[index].m_eBlipDisplay = display;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ChangeBlipScale(int32, int32) { EAXJMP(0x4A57E0); }
+#else
+void CRadar::ChangeBlipScale(int32 i, int32 scale)
+{
 	int index = GetActualBlipArrayIndex(i);
 	if (index != -1)
-		ms_RadarTrace[index].m_wScale = scale;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ClearBlip(int32) { EAXJMP(0x4A5720); }
-#else
-void CRadar::ClearBlip(int32 i)
-{
+		ms_RadarTrace[index].m_wScale = scale;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ClearBlip(int32) { EAXJMP(0x4A5720); }
+#else
+void CRadar::ClearBlip(int32 i)
+{
 	int index = GetActualBlipArrayIndex(i);
 	if (index != -1) {
 		SetRadarMarkerState(index, false);
@@ -146,127 +146,127 @@ void CRadar::ClearBlip(int32 i)
 		ms_RadarTrace[index].m_eBlipType = BLIP_NONE;
 		ms_RadarTrace[index].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
 		ms_RadarTrace[index].m_IconID = RADAR_SPRITE_NONE;
-	}
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ClearBlipForEntity(eBlipType, int32) { EAXJMP(0x4A56C0); }
-#else
-void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
-{
-	for (int i = 0; i < NUMRADARBLIPS; i++) {
-		if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) {
-			SetRadarMarkerState(i, false);
-			ms_RadarTrace[i].m_bInUse = false;
-			ms_RadarTrace[i].m_eBlipType = BLIP_NONE;
-			ms_RadarTrace[i].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
-			ms_RadarTrace[i].m_IconID = RADAR_SPRITE_NONE;
-		}
-	};
-}
-#endif
-
-#if 0
-WRAPPER int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *in) { EAXJMP(0x4A64A0); }
-#else
-// Why not a proper clipping algorithm?
-int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
-{
-	CVector2D corners[4] = {
-		{  1.0f, -1.0f },	// top right
-		{  1.0f,  1.0f },	// bottom right
-		{ -1.0f,  1.0f },	// bottom left
-		{ -1.0f, -1.0f },	// top left
-	};
-	CVector2D tmp;
-	int i, j, n;
-	int laste, e, e1, e2;;
-	bool inside[4];
-
-	for (i = 0; i < 4; i++)
-		inside[i] = IsPointInsideRadar(rect[i]);
-
-	laste = -1;
-	n = 0;
-	for (i = 0; i < 4; i++)
-		if (inside[i]) {
-			// point is inside, just add
-			poly[n++] = rect[i];
-		}
-		else {
-			// point is outside but line to this point might be clipped
-			e1 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 4 - 1) % 4]);
-			if (e1 != -1) {
-				laste = e1;
-				n++;
-			}
-			// and line from this point might be clipped as well
-			e2 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 1) % 4]);
-			if (e2 != -1) {
-				if (e1 == -1) {
-					// if other line wasn't clipped, i.e. it was complete outside,
-					// we may have to insert another vertex if last clipped line
-					// was on a different edge
-
-					// find the last intersection if we haven't seen it yet
-					if (laste == -1)
-						for (j = 3; j >= i; j--) {
-							// game uses an if here for j == 0
-							e = LineRadarBoxCollision(tmp, rect[j], rect[(j + 4 - 1) % 4]);
-							if (e != -1) {
-								laste = e;
-								break;
-							}
-						}
-					assert(laste != -1);
-
-					// insert corners that were skipped
-					tmp = poly[n];
-					for (e = laste; e != e2; e = (e + 1) % 4)
-						poly[n++] = corners[e];
-					poly[n] = tmp;
-				}
-				n++;
-			}
-		}
-
-	if (n == 0) {
-		// If no points, either the rectangle is completely outside or completely surrounds the radar
-		// no idea what's going on here...
-		float m = (rect[0].y - rect[1].y) / (rect[0].x - rect[1].x);
-		if ((m*rect[3].x - rect[3].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
-			m = (rect[0].y - rect[3].y) / (rect[0].x - rect[3].x);
-			if ((m*rect[1].x - rect[1].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
-				poly[0] = corners[0];
-				poly[1] = corners[1];
-				poly[2] = corners[2];
-				poly[3] = corners[3];
-				n = 4;
-			}
-		}
-	}
-
-	return n;
-}
-#endif
-
-bool CRadar::DisplayThisBlip(int32 counter)
-{
-	switch (ms_RadarTrace[counter].m_IconID) {
-	case RADAR_SPRITE_BOMB:
-	case RADAR_SPRITE_SPRAY:
-	case RADAR_SPRITE_WEAPON:
-		return true;
-	default:
-		return false;
-	}
-}
-
-#if 0
-WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); }
-#else
-void CRadar::Draw3dMarkers()
+	}
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ClearBlipForEntity(eBlipType, int32) { EAXJMP(0x4A56C0); }
+#else
+void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
+{
+	for (int i = 0; i < NUMRADARBLIPS; i++) {
+		if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) {
+			SetRadarMarkerState(i, false);
+			ms_RadarTrace[i].m_bInUse = false;
+			ms_RadarTrace[i].m_eBlipType = BLIP_NONE;
+			ms_RadarTrace[i].m_eBlipDisplay = BLIP_DISPLAY_NEITHER;
+			ms_RadarTrace[i].m_IconID = RADAR_SPRITE_NONE;
+		}
+	};
+}
+#endif
+
+#if 0
+WRAPPER int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *in) { EAXJMP(0x4A64A0); }
+#else
+// Why not a proper clipping algorithm?
+int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
+{
+	CVector2D corners[4] = {
+		{  1.0f, -1.0f },	// top right
+		{  1.0f,  1.0f },	// bottom right
+		{ -1.0f,  1.0f },	// bottom left
+		{ -1.0f, -1.0f },	// top left
+	};
+	CVector2D tmp;
+	int i, j, n;
+	int laste, e, e1, e2;;
+	bool inside[4];
+
+	for (i = 0; i < 4; i++)
+		inside[i] = IsPointInsideRadar(rect[i]);
+
+	laste = -1;
+	n = 0;
+	for (i = 0; i < 4; i++)
+		if (inside[i]) {
+			// point is inside, just add
+			poly[n++] = rect[i];
+		}
+		else {
+			// point is outside but line to this point might be clipped
+			e1 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 4 - 1) % 4]);
+			if (e1 != -1) {
+				laste = e1;
+				n++;
+			}
+			// and line from this point might be clipped as well
+			e2 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 1) % 4]);
+			if (e2 != -1) {
+				if (e1 == -1) {
+					// if other line wasn't clipped, i.e. it was complete outside,
+					// we may have to insert another vertex if last clipped line
+					// was on a different edge
+
+					// find the last intersection if we haven't seen it yet
+					if (laste == -1)
+						for (j = 3; j >= i; j--) {
+							// game uses an if here for j == 0
+							e = LineRadarBoxCollision(tmp, rect[j], rect[(j + 4 - 1) % 4]);
+							if (e != -1) {
+								laste = e;
+								break;
+							}
+						}
+					assert(laste != -1);
+
+					// insert corners that were skipped
+					tmp = poly[n];
+					for (e = laste; e != e2; e = (e + 1) % 4)
+						poly[n++] = corners[e];
+					poly[n] = tmp;
+				}
+				n++;
+			}
+		}
+
+	if (n == 0) {
+		// If no points, either the rectangle is completely outside or completely surrounds the radar
+		// no idea what's going on here...
+		float m = (rect[0].y - rect[1].y) / (rect[0].x - rect[1].x);
+		if ((m*rect[3].x - rect[3].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
+			m = (rect[0].y - rect[3].y) / (rect[0].x - rect[3].x);
+			if ((m*rect[1].x - rect[1].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
+				poly[0] = corners[0];
+				poly[1] = corners[1];
+				poly[2] = corners[2];
+				poly[3] = corners[3];
+				n = 4;
+			}
+		}
+	}
+
+	return n;
+}
+#endif
+
+bool CRadar::DisplayThisBlip(int32 counter)
+{
+	switch (ms_RadarTrace[counter].m_IconID) {
+	case RADAR_SPRITE_BOMB:
+	case RADAR_SPRITE_SPRAY:
+	case RADAR_SPRITE_WEAPON:
+		return true;
+	default:
+		return false;
+	}
+}
+
+#if 0
+WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); }
+#else
+void CRadar::Draw3dMarkers()
 {
 	for (int i = 0; i < NUMRADARBLIPS; i++) {
 		if (ms_RadarTrace[i].m_bInUse) {
@@ -315,556 +315,556 @@ void CRadar::Draw3dMarkers()
 				break;
 			}
 		}
-	}
-}
-#endif
-
-
-#if 0
-WRAPPER void CRadar::DrawBlips() { EAXJMP(0x4A42F0); }
-#else
-void CRadar::DrawBlips()
-{
-	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
-		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
-		RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
-		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
-		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
-		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
-
-		CVector2D out;
-		CVector2D in = CVector2D(0.0f, 0.0f);
-		TransformRadarPointToScreenSpace(out, in);
-
-		float angle;
-		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN)
-			angle = PI + FindPlayerHeading();
-#ifdef FIX_BUGS
-		else if (TheCamera.GetLookDirection() != LOOKING_FORWARD)
-			angle = FindPlayerHeading() - (PI + (TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind).Heading());
-#endif
-		else
-			angle = FindPlayerHeading() - (PI + TheCamera.GetForward().Heading());
-
-		DrawRotatingRadarSprite(&CentreSprite, out.x, out.y, angle, 255);
-
-		CVector2D vec2d;
-		vec2d.x = vec2DRadarOrigin.x;
-		vec2d.y = M_SQRT2 * m_radarRange + vec2DRadarOrigin.y;
-		TransformRealWorldPointToRadarSpace(in, vec2d);
-		LimitRadarPoint(in);
-		TransformRadarPointToScreenSpace(out, in);
-		DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255);
-
-		CEntity *blipEntity = nil;
-		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
-			if (!ms_RadarTrace[blipId].m_bInUse)
-				continue;
-
-			switch (ms_RadarTrace[blipId].m_eBlipType) {
-				case BLIP_CAR:
-				case BLIP_CHAR:
-				case BLIP_OBJECT:
-					if (ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SAVE
-						|| ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_WEAPON) {
-
-						switch (ms_RadarTrace[blipId].m_eBlipType) {
-							case BLIP_CAR:
-								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							case BLIP_CHAR:
+	}
+}
+#endif
+
+
+#if 0
+WRAPPER void CRadar::DrawBlips() { EAXJMP(0x4A42F0); }
+#else
+void CRadar::DrawBlips()
+{
+	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
+		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+		RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+		RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+		RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+
+		CVector2D out;
+		CVector2D in = CVector2D(0.0f, 0.0f);
+		TransformRadarPointToScreenSpace(out, in);
+
+		float angle;
+		if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN)
+			angle = PI + FindPlayerHeading();
+#ifdef FIX_BUGS
+		else if (TheCamera.GetLookDirection() != LOOKING_FORWARD)
+			angle = FindPlayerHeading() - (PI + (TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind).Heading());
+#endif
+		else
+			angle = FindPlayerHeading() - (PI + TheCamera.GetForward().Heading());
+
+		DrawRotatingRadarSprite(&CentreSprite, out.x, out.y, angle, 255);
+
+		CVector2D vec2d;
+		vec2d.x = vec2DRadarOrigin.x;
+		vec2d.y = M_SQRT2 * m_radarRange + vec2DRadarOrigin.y;
+		TransformRealWorldPointToRadarSpace(in, vec2d);
+		LimitRadarPoint(in);
+		TransformRadarPointToScreenSpace(out, in);
+		DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255);
+
+		CEntity *blipEntity = nil;
+		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
+			if (!ms_RadarTrace[blipId].m_bInUse)
+				continue;
+
+			switch (ms_RadarTrace[blipId].m_eBlipType) {
+				case BLIP_CAR:
+				case BLIP_CHAR:
+				case BLIP_OBJECT:
+					if (ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SAVE
+						|| ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_WEAPON) {
+
+						switch (ms_RadarTrace[blipId].m_eBlipType) {
+							case BLIP_CAR:
+								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							case BLIP_CHAR:
 								blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
 								if (blipEntity != nil) {
 									if (((CPed*)blipEntity)->InVehicle())
 										blipEntity = ((CPed*)blipEntity)->m_pMyVehicle;
-								}
-								break;
-							case BLIP_OBJECT:
-								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							default:
-								break;
-						}
-						if (blipEntity) {
-							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-								if (CTheScripts::IsDebugOn()) {
-									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
-									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-										ms_RadarTrace[blipId].m_Radius = 5.0f;
-								}
-							}
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
-								float dist = LimitRadarPoint(in);
-								TransformRadarPointToScreenSpace(out, in);
-								if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE) {
-									DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-								} else {
-#ifdef TRIANGULAR_BLIPS
-									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-									CVector &blipPos = blipEntity->GetPosition();
-									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+								}
+								break;
+							case BLIP_OBJECT:
+								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							default:
+								break;
+						}
+						if (blipEntity) {
+							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+								if (CTheScripts::IsDebugOn()) {
+									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
+									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+										ms_RadarTrace[blipId].m_Radius = 5.0f;
+								}
+							}
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
+								float dist = LimitRadarPoint(in);
+								TransformRadarPointToScreenSpace(out, in);
+								if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE) {
+									DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
+								} else {
+#ifdef TRIANGULAR_BLIPS
+									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+									CVector &blipPos = blipEntity->GetPosition();
+									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
 									if (blipPos.z - pos.z <= 2.0f) {
 										if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
 										else mode = BLIP_MODE_SQUARE;
-									}
-									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-#else
-									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-								}
-							}
-						}
-					}
-					break;
-				case BLIP_COORD:
-				case BLIP_CONTACT_POINT:
-					if ((ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SAVE
-						|| ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_WEAPON)
-						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
-
-						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-							if (CTheScripts::IsDebugOn()) {
-								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
-								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-									ms_RadarTrace[blipId].m_Radius = 5.0f;
-							}
-						}
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
-							float dist = LimitRadarPoint(in);
-							TransformRadarPointToScreenSpace(out, in);
-							if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE) {
-								DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-							} else {
-#ifdef TRIANGULAR_BLIPS
-								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
-								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+									}
+									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+#else
+									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+								}
+							}
+						}
+					}
+					break;
+				case BLIP_COORD:
+				case BLIP_CONTACT_POINT:
+					if ((ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_BOMB || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SAVE
+						|| ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_SPRAY || ms_RadarTrace[blipId].m_IconID == RADAR_SPRITE_WEAPON)
+						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
+
+						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+							if (CTheScripts::IsDebugOn()) {
+								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
+								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+									ms_RadarTrace[blipId].m_Radius = 5.0f;
+							}
+						}
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
+							float dist = LimitRadarPoint(in);
+							TransformRadarPointToScreenSpace(out, in);
+							if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE) {
+								DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
+							} else {
+#ifdef TRIANGULAR_BLIPS
+								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
+								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
 								if (blipPos.z - pos.z <= 2.0f) {
 									if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
 									else mode = BLIP_MODE_SQUARE;
-								}
-								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-#else
-								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-							}
-						}
-					}
-					break;
-				default:
-					break;
-			}
-		}
-		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
-			if (!ms_RadarTrace[blipId].m_bInUse)
-				continue;
-
-			switch (ms_RadarTrace[blipId].m_eBlipType) {
-				case BLIP_CAR:
-				case BLIP_CHAR:
-				case BLIP_OBJECT:
-					if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SAVE
-						&& ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_WEAPON) {
-
-						switch (ms_RadarTrace[blipId].m_eBlipType) {
-							case BLIP_CAR:
-								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							case BLIP_CHAR:
+								}
+								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+#else
+								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+							}
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+		for(int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
+			if (!ms_RadarTrace[blipId].m_bInUse)
+				continue;
+
+			switch (ms_RadarTrace[blipId].m_eBlipType) {
+				case BLIP_CAR:
+				case BLIP_CHAR:
+				case BLIP_OBJECT:
+					if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SAVE
+						&& ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_WEAPON) {
+
+						switch (ms_RadarTrace[blipId].m_eBlipType) {
+							case BLIP_CAR:
+								blipEntity = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							case BLIP_CHAR:
 								blipEntity = CPools::GetPedPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
 								if (blipEntity != nil) {
 									if (((CPed*)blipEntity)->InVehicle())
 										blipEntity = ((CPed*)blipEntity)->m_pMyVehicle;
-								}
-								break;
-							case BLIP_OBJECT:
-								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
-								break;
-							default:
-								break;
-						}
-
-						if (blipEntity) {
-							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-								if (CTheScripts::IsDebugOn()) {
-									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
-									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-										ms_RadarTrace[blipId].m_Radius = 5.0f;
-								}
-							}
-							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
-								float dist = LimitRadarPoint(in);
-								TransformRadarPointToScreenSpace(out, in);
-								if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE)
-									DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-								else
-#ifdef TRIANGULAR_BLIPS
-								{
-									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-									CVector &blipPos = blipEntity->GetPosition();
-									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+								}
+								break;
+							case BLIP_OBJECT:
+								blipEntity = CPools::GetObjectPool()->GetAt(ms_RadarTrace[blipId].m_nEntityHandle);
+								break;
+							default:
+								break;
+						}
+
+						if (blipEntity) {
+							uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+								if (CTheScripts::IsDebugOn()) {
+									ShowRadarMarker(blipEntity->GetPosition(), color, ms_RadarTrace[blipId].m_Radius);
+									ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+									if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+										ms_RadarTrace[blipId].m_Radius = 5.0f;
+								}
+							}
+							if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+								TransformRealWorldPointToRadarSpace(in, blipEntity->GetPosition());
+								float dist = LimitRadarPoint(in);
+								TransformRadarPointToScreenSpace(out, in);
+								if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE)
+									DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
+								else
+#ifdef TRIANGULAR_BLIPS
+								{
+									CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+									CVector &blipPos = blipEntity->GetPosition();
+									uint8 mode = BLIP_MODE_TRIANGULAR_UP;
 									if (blipPos.z - pos.z <= 2.0f) {
 										if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
 										else mode = BLIP_MODE_SQUARE;
-									}
-									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-								}
-#else
-									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-							}
-						}
-					}
-					break;
-				default:
-					break;
-			}
-		}
-		for (int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
-			if (!ms_RadarTrace[blipId].m_bInUse)
-				continue;
-
-			switch (ms_RadarTrace[blipId].m_eBlipType) {
-				case BLIP_COORD:
-				case BLIP_CONTACT_POINT:
-					if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SAVE
-						&& ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_WEAPON
-						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
-
-						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
-							if (CTheScripts::IsDebugOn()) {
-								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
-								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
-								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
-									ms_RadarTrace[blipId].m_Radius = 5.0f;
-							}
-						}
-						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
-							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
-							float dist = LimitRadarPoint(in);
-							TransformRadarPointToScreenSpace(out, in);
-							if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE)
-								DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
-							else
-#ifdef TRIANGULAR_BLIPS
-							{
-								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
-								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
-								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
+									}
+									ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+								}
+#else
+									ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+							}
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+		for (int blipId = 0; blipId < NUMRADARBLIPS; blipId++) {
+			if (!ms_RadarTrace[blipId].m_bInUse)
+				continue;
+
+			switch (ms_RadarTrace[blipId].m_eBlipType) {
+				case BLIP_COORD:
+				case BLIP_CONTACT_POINT:
+					if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_BOMB && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SAVE
+						&& ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_SPRAY && ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_WEAPON
+						&& (ms_RadarTrace[blipId].m_eBlipType != BLIP_CONTACT_POINT || !CTheScripts::IsPlayerOnAMission())) {
+
+						uint32 color = GetRadarTraceColour(ms_RadarTrace[blipId].m_nColor, ms_RadarTrace[blipId].m_bDim);
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
+							if (CTheScripts::IsDebugOn()) {
+								ShowRadarMarker(ms_RadarTrace[blipId].m_vecPos, color, ms_RadarTrace[blipId].m_Radius);
+								ms_RadarTrace[blipId].m_Radius = ms_RadarTrace[blipId].m_Radius - 0.1f;
+								if (ms_RadarTrace[blipId].m_Radius < 1.0f)
+									ms_RadarTrace[blipId].m_Radius = 5.0f;
+							}
+						}
+						if (ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[blipId].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
+							TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[blipId].m_vec2DPos);
+							float dist = LimitRadarPoint(in);
+							TransformRadarPointToScreenSpace(out, in);
+							if (ms_RadarTrace[blipId].m_IconID != RADAR_SPRITE_NONE)
+								DrawRadarSprite(ms_RadarTrace[blipId].m_IconID, out.x, out.y, CalculateBlipAlpha(dist));
+							else
+#ifdef TRIANGULAR_BLIPS
+							{
+								CVector &pos = FindPlayerCentreOfWorld_NoSniperShift();
+								CVector &blipPos = ms_RadarTrace[blipId].m_vecPos;
+								uint8 mode = BLIP_MODE_TRIANGULAR_UP;
 								if (blipPos.z - pos.z <= 2.0f) {
 									if (blipPos.z - pos.z < -4.0f) mode = BLIP_MODE_TRIANGULAR_DOWN;
 									else mode = BLIP_MODE_SQUARE;
-								}
-								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
-							}
-#else
-								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
-#endif
-						}
-					}
-					break;
-				default:
-					break;
-			}
-		}
-	}
-}
-#endif
-
-
-#if 0
-WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); }
-#else
-void CRadar::DrawMap()
-{
-	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
-		if (FindPlayerVehicle()) {
-			float speed = FindPlayerSpeed().Magnitude();
-			if (speed < RADAR_MIN_SPEED)
-				m_radarRange = RADAR_MIN_RANGE;
-			else if (speed < RADAR_MAX_SPEED)
-				m_radarRange = (speed - RADAR_MIN_SPEED)/(RADAR_MAX_SPEED-RADAR_MIN_SPEED) * (RADAR_MAX_RANGE-RADAR_MIN_RANGE) + RADAR_MIN_RANGE;
-			else
-				m_radarRange = RADAR_MAX_RANGE;
-		}
-		else
-			m_radarRange = RADAR_MIN_RANGE;
-
-		vec2DRadarOrigin = CVector2D(FindPlayerCentreOfWorld_NoSniperShift());
-		DrawRadarMap();
-	}
-}
-#endif 
-
-#if 0
-WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); }
-#else
-void CRadar::DrawRadarMap()
-{
-	// Game calculates an unused CRect here
-
-	DrawRadarMask();
-
-	// top left ist (0, 0)
-	int x = floorf((vec2DRadarOrigin.x - WORLD_MIN_X) / RADAR_TILE_SIZE);
-	int y = ceilf((RADAR_NUM_TILES - 1) - (vec2DRadarOrigin.y - WORLD_MIN_Y) / RADAR_TILE_SIZE);
-	StreamRadarSections(x, y);
-
-	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
-	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
-	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
-	RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE);
-
-	DrawRadarSection(x - 1, y - 1);
-	DrawRadarSection(x, y - 1);
-	DrawRadarSection(x + 1, y - 1);
-	DrawRadarSection(x - 1, y);
-	DrawRadarSection(x, y);
-	DrawRadarSection(x + 1, y);
-	DrawRadarSection(x - 1, y + 1);
-	DrawRadarSection(x, y + 1);
-	DrawRadarSection(x + 1, y + 1);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); }
-#else
-void CRadar::DrawRadarMask() 
-{ 
-	CVector2D corners[4] = {
-		CVector2D(1.0f, -1.0f),
-		CVector2D(1.0f, 1.0f),
-		CVector2D(-1.0f, 1.0f),
-		CVector2D(-1.0, -1.0f)
-	};
-
-	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
-	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
-	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
-	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
-	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
-	RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONALWAYS);
-
-	CVector2D out[8];
-	CVector2D in;
-
-	// Draw the shape we want to mask out from the radar in four segments
-	for (int i = 0; i < 4; i++) {
-		// First point is always the corner itself
-		in.x = corners[i].x;
-		in.y = corners[i].y;
-		TransformRadarPointToScreenSpace(out[0], in);
-
-		// Then generate a quarter of the circle
-		for (int j = 0; j < 7; j++) {
-			in.x = corners[i].x * Cos(j * (PI / 2.0f / 6.0f));
-			in.y = corners[i].y * Sin(j * (PI / 2.0f / 6.0f));
-			TransformRadarPointToScreenSpace(out[j + 1], in);
-		};
-
-		CSprite2d::SetMaskVertices(8, (float *)out);
-		RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8);
-	};
-
-	RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawRadarSection(int32, int32) { EAXJMP(0x4A67E0); }
-#else
-void CRadar::DrawRadarSection(int32 x, int32 y)
-{
-	int i;
-	RwTexDictionary *txd;
-	CVector2D worldPoly[8];
-	CVector2D radarCorners[4];
-	CVector2D radarPoly[8];
-	CVector2D texCoords[8];
-	CVector2D screenPoly[8];
-	int numVertices;
-	RwTexture *texture = nil;
-
-	GetTextureCorners(x, y, worldPoly);
-	ClipRadarTileCoords(x, y);
-
-	assert(CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y]));
-	txd = CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])->texDict;
-	if (txd)
-		texture = GetFirstTexture(txd);
-	if (texture == nil)
-		return;
-
-	for (i = 0; i < 4; i++)
-		TransformRealWorldPointToRadarSpace(radarCorners[i], worldPoly[i]);
-
-	numVertices = ClipRadarPoly(radarPoly, radarCorners);
-
-	// FIX: can return earlier here
-//	if(numVertices == 0)
-	if (numVertices < 3)
-		return;
-
-	for (i = 0; i < numVertices; i++) {
-		TransformRadarPointToRealWorldSpace(worldPoly[i], radarPoly[i]);
-		TransformRealWorldToTexCoordSpace(texCoords[i], worldPoly[i], x, y);
-		TransformRadarPointToScreenSpace(screenPoly[i], radarPoly[i]);
-	}
-	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(texture));
-	CSprite2d::SetVertices(numVertices, (float*)screenPoly, (float*)texCoords, CRGBA(255, 255, 255, 255));
-	// check done above now
-//	if(numVertices > 2)
-	RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha) { EAXJMP(0x4A5EF0); }
-#else
-void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha)
-{
-	RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) { EAXJMP(0x4A5D10); }
-#else
-void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha)
-{
-	CVector curPosn[4];
-	CVector oldPosn[4];
-
-	curPosn[0].x = x - SCREEN_SCALE_X(5.6f);
-	curPosn[0].y = y + SCREEN_SCALE_Y(5.6f);
-
-	curPosn[1].x = x + SCREEN_SCALE_X(5.6f);
-	curPosn[1].y = y + SCREEN_SCALE_Y(5.6f);
-
-	curPosn[2].x = x - SCREEN_SCALE_X(5.6f);
-	curPosn[2].y = y - SCREEN_SCALE_Y(5.6f);
-
-	curPosn[3].x = x + SCREEN_SCALE_X(5.6f);
-	curPosn[3].y = y - SCREEN_SCALE_Y(5.6f);
-
-	for (uint32 i = 0; i < 4; i++) {
-		oldPosn[i] = curPosn[i];
-
-		curPosn[i].x = x + (oldPosn[i].x - x) * Cos(angle) + (oldPosn[i].y - y) * Sin(angle);
-		curPosn[i].y = y - (oldPosn[i].x - x) * Sin(angle) + (oldPosn[i].y - y) * Cos(angle);
-	}
-
-	sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
-}
-#endif 
-
-#if 0
-WRAPPER int32 CRadar::GetActualBlipArrayIndex(int32) { EAXJMP(0x4A41C0); }
-#else
-int32 CRadar::GetActualBlipArrayIndex(int32 i)
-{
-	if (i == -1)
-		return -1;
-	else if ((i & 0xFFFF0000) >> 16 != ms_RadarTrace[(uint16)i].m_BlipIndex)
-		return -1;
-	else
-		return (uint16)i;
-}
-#endif
-
-#if 0
-WRAPPER int32 CRadar::GetNewUniqueBlipIndex(int32) { EAXJMP(0x4A4180); }
-#else
-int32 CRadar::GetNewUniqueBlipIndex(int32 i)
+								}
+								ShowRadarTraceWithHeight(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255, mode);
+							}
+#else
+								ShowRadarTrace(out.x, out.y, ms_RadarTrace[blipId].m_wScale, (uint8)(color >> 24), (uint8)(color >> 16), (uint8)(color >> 8), 255);
+#endif
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+	}
+}
+#endif
+
+
+#if 0
+WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); }
+#else
+void CRadar::DrawMap()
+{
+	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
+		if (FindPlayerVehicle()) {
+			float speed = FindPlayerSpeed().Magnitude();
+			if (speed < RADAR_MIN_SPEED)
+				m_radarRange = RADAR_MIN_RANGE;
+			else if (speed < RADAR_MAX_SPEED)
+				m_radarRange = (speed - RADAR_MIN_SPEED)/(RADAR_MAX_SPEED-RADAR_MIN_SPEED) * (RADAR_MAX_RANGE-RADAR_MIN_RANGE) + RADAR_MIN_RANGE;
+			else
+				m_radarRange = RADAR_MAX_RANGE;
+		}
+		else
+			m_radarRange = RADAR_MIN_RANGE;
+
+		vec2DRadarOrigin = CVector2D(FindPlayerCentreOfWorld_NoSniperShift());
+		DrawRadarMap();
+	}
+}
+#endif 
+
+#if 0
+WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); }
+#else
+void CRadar::DrawRadarMap()
+{
+	// Game calculates an unused CRect here
+
+	DrawRadarMask();
+
+	// top left ist (0, 0)
+	int x = floorf((vec2DRadarOrigin.x - WORLD_MIN_X) / RADAR_TILE_SIZE);
+	int y = ceilf((RADAR_NUM_TILES - 1) - (vec2DRadarOrigin.y - WORLD_MIN_Y) / RADAR_TILE_SIZE);
+	StreamRadarSections(x, y);
+
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+	RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE);
+
+	DrawRadarSection(x - 1, y - 1);
+	DrawRadarSection(x, y - 1);
+	DrawRadarSection(x + 1, y - 1);
+	DrawRadarSection(x - 1, y);
+	DrawRadarSection(x, y);
+	DrawRadarSection(x + 1, y);
+	DrawRadarSection(x - 1, y + 1);
+	DrawRadarSection(x, y + 1);
+	DrawRadarSection(x + 1, y + 1);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); }
+#else
+void CRadar::DrawRadarMask() 
+{ 
+	CVector2D corners[4] = {
+		CVector2D(1.0f, -1.0f),
+		CVector2D(1.0f, 1.0f),
+		CVector2D(-1.0f, 1.0f),
+		CVector2D(-1.0, -1.0f)
+	};
+
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONALWAYS);
+
+	CVector2D out[8];
+	CVector2D in;
+
+	// Draw the shape we want to mask out from the radar in four segments
+	for (int i = 0; i < 4; i++) {
+		// First point is always the corner itself
+		in.x = corners[i].x;
+		in.y = corners[i].y;
+		TransformRadarPointToScreenSpace(out[0], in);
+
+		// Then generate a quarter of the circle
+		for (int j = 0; j < 7; j++) {
+			in.x = corners[i].x * Cos(j * (PI / 2.0f / 6.0f));
+			in.y = corners[i].y * Sin(j * (PI / 2.0f / 6.0f));
+			TransformRadarPointToScreenSpace(out[j + 1], in);
+		};
+
+		CSprite2d::SetMaskVertices(8, (float *)out);
+		RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8);
+	};
+
+	RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRadarSection(int32, int32) { EAXJMP(0x4A67E0); }
+#else
+void CRadar::DrawRadarSection(int32 x, int32 y)
+{
+	int i;
+	RwTexDictionary *txd;
+	CVector2D worldPoly[8];
+	CVector2D radarCorners[4];
+	CVector2D radarPoly[8];
+	CVector2D texCoords[8];
+	CVector2D screenPoly[8];
+	int numVertices;
+	RwTexture *texture = nil;
+
+	GetTextureCorners(x, y, worldPoly);
+	ClipRadarTileCoords(x, y);
+
+	assert(CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y]));
+	txd = CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])->texDict;
+	if (txd)
+		texture = GetFirstTexture(txd);
+	if (texture == nil)
+		return;
+
+	for (i = 0; i < 4; i++)
+		TransformRealWorldPointToRadarSpace(radarCorners[i], worldPoly[i]);
+
+	numVertices = ClipRadarPoly(radarPoly, radarCorners);
+
+	// FIX: can return earlier here
+//	if(numVertices == 0)
+	if (numVertices < 3)
+		return;
+
+	for (i = 0; i < numVertices; i++) {
+		TransformRadarPointToRealWorldSpace(worldPoly[i], radarPoly[i]);
+		TransformRealWorldToTexCoordSpace(texCoords[i], worldPoly[i], x, y);
+		TransformRadarPointToScreenSpace(screenPoly[i], radarPoly[i]);
+	}
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(texture));
+	CSprite2d::SetVertices(numVertices, (float*)screenPoly, (float*)texCoords, CRGBA(255, 255, 255, 255));
+	// check done above now
+//	if(numVertices > 2)
+	RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha) { EAXJMP(0x4A5EF0); }
+#else
+void CRadar::DrawRadarSprite(uint16 sprite, float x, float y, uint8 alpha)
+{
+	RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) { EAXJMP(0x4A5D10); }
+#else
+void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha)
+{
+	CVector curPosn[4];
+	CVector oldPosn[4];
+
+	curPosn[0].x = x - SCREEN_SCALE_X(5.6f);
+	curPosn[0].y = y + SCREEN_SCALE_Y(5.6f);
+
+	curPosn[1].x = x + SCREEN_SCALE_X(5.6f);
+	curPosn[1].y = y + SCREEN_SCALE_Y(5.6f);
+
+	curPosn[2].x = x - SCREEN_SCALE_X(5.6f);
+	curPosn[2].y = y - SCREEN_SCALE_Y(5.6f);
+
+	curPosn[3].x = x + SCREEN_SCALE_X(5.6f);
+	curPosn[3].y = y - SCREEN_SCALE_Y(5.6f);
+
+	for (uint32 i = 0; i < 4; i++) {
+		oldPosn[i] = curPosn[i];
+
+		curPosn[i].x = x + (oldPosn[i].x - x) * Cos(angle) + (oldPosn[i].y - y) * Sin(angle);
+		curPosn[i].y = y - (oldPosn[i].x - x) * Sin(angle) + (oldPosn[i].y - y) * Cos(angle);
+	}
+
+	sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
+}
+#endif 
+
+#if 0
+WRAPPER int32 CRadar::GetActualBlipArrayIndex(int32) { EAXJMP(0x4A41C0); }
+#else
+int32 CRadar::GetActualBlipArrayIndex(int32 i)
+{
+	if (i == -1)
+		return -1;
+	else if ((i & 0xFFFF0000) >> 16 != ms_RadarTrace[(uint16)i].m_BlipIndex)
+		return -1;
+	else
+		return (uint16)i;
+}
+#endif
+
+#if 0
+WRAPPER int32 CRadar::GetNewUniqueBlipIndex(int32) { EAXJMP(0x4A4180); }
+#else
+int32 CRadar::GetNewUniqueBlipIndex(int32 i)
 {
 	if (ms_RadarTrace[i].m_BlipIndex >= UINT16_MAX - 1)
 		ms_RadarTrace[i].m_BlipIndex = 1;
 	else
 		ms_RadarTrace[i].m_BlipIndex++;
-	return i | (ms_RadarTrace[i].m_BlipIndex << 16);
-}
-#endif
-
-#if 0
-WRAPPER uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright) { EAXJMP(0x4A5BB0); }
-#else
-uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright)
-{
-	int32 c;
-	switch (color) {
-	case 0:
-		if (bright)
-			c = 0x712B49FF;
-		else
-			c = 0x7F0000FF;
-		break;
-	case 1:
-		if (bright)
-			c = 0x5FA06AFF;
-		else
-			c = 0x007F00FF;
-		break;
-	case 2:
-		if (bright)
-			c = 0x80A7F3FF;
-		else
-			c = 0x00007FFF;
-		break;
-	case 3:
-		if (bright)
-			c = 0xE1E1E1FF;
-		else
-			c = 0x7F7F7FFF;
-		break;
-	case 4:
-		if (bright)
-			c = 0xFFFF00FF;
-		else
-			c = 0x7F7F00FF;
-		break;
-	case 5:
-		if (bright)
-			c = 0xFF00FFFF;
-		else
-			c = 0x7F007FFF;
-		break;
-	case 6:
-		if (bright)
-			c = 0x00FFFFFF;
-		else
-			c = 0x007F7FFF;
-		break;
-	default:
-		c = color;
-		break;
-	};
-	return c;
-}
-#endif
-
-const char* gRadarTexNames[] = {
+	return i | (ms_RadarTrace[i].m_BlipIndex << 16);
+}
+#endif
+
+#if 0
+WRAPPER uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright) { EAXJMP(0x4A5BB0); }
+#else
+uint32 CRadar::GetRadarTraceColour(uint32 color, bool bright)
+{
+	int32 c;
+	switch (color) {
+	case 0:
+		if (bright)
+			c = 0x712B49FF;
+		else
+			c = 0x7F0000FF;
+		break;
+	case 1:
+		if (bright)
+			c = 0x5FA06AFF;
+		else
+			c = 0x007F00FF;
+		break;
+	case 2:
+		if (bright)
+			c = 0x80A7F3FF;
+		else
+			c = 0x00007FFF;
+		break;
+	case 3:
+		if (bright)
+			c = 0xE1E1E1FF;
+		else
+			c = 0x7F7F7FFF;
+		break;
+	case 4:
+		if (bright)
+			c = 0xFFFF00FF;
+		else
+			c = 0x7F7F00FF;
+		break;
+	case 5:
+		if (bright)
+			c = 0xFF00FFFF;
+		else
+			c = 0x7F007FFF;
+		break;
+	case 6:
+		if (bright)
+			c = 0x00FFFFFF;
+		else
+			c = 0x007F7FFF;
+		break;
+	default:
+		c = color;
+		break;
+	};
+	return c;
+}
+#endif
+
+const char* gRadarTexNames[] = {
 	"radar00", "radar01", "radar02", "radar03", "radar04", "radar05", "radar06", "radar07",
 	"radar08", "radar09", "radar10", "radar11", "radar12", "radar13", "radar14", "radar15",
 	"radar16", "radar17", "radar18", "radar19", "radar20", "radar21", "radar22", "radar23",
@@ -872,14 +872,14 @@ const char* gRadarTexNames[] = {
 	"radar32", "radar33", "radar34", "radar35", "radar36", "radar37", "radar38", "radar39",
 	"radar40", "radar41", "radar42", "radar43", "radar44", "radar45", "radar46", "radar47",
 	"radar48", "radar49", "radar50", "radar51", "radar52", "radar53", "radar54", "radar55",
-	"radar56", "radar57", "radar58", "radar59", "radar60", "radar61", "radar62", "radar63",
-};
-
-#if 0
-WRAPPER void CRadar::Initialise() { EAXJMP(0x4A3EF0); }
-#else
-void
-CRadar::Initialise()
+	"radar56", "radar57", "radar58", "radar59", "radar60", "radar61", "radar62", "radar63",
+};
+
+#if 0
+WRAPPER void CRadar::Initialise() { EAXJMP(0x4A3EF0); }
+#else
+void
+CRadar::Initialise()
 {
 	for (int i = 0; i < NUMRADARBLIPS; i++) {
 		ms_RadarTrace[i].m_BlipIndex = 1;
@@ -892,49 +892,49 @@ CRadar::Initialise()
 
 	m_radarRange = 350.0f;
 	for (int i = 0; i < 64; i++) 
-		gRadarTxdIds[i] = CTxdStore::FindTxdSlot(gRadarTexNames[i]);
-}
-#endif
-
-#if 0
-WRAPPER float CRadar::LimitRadarPoint(CVector2D &point) { EAXJMP(0x4A4F30); }
-#else
-float CRadar::LimitRadarPoint(CVector2D &point)
-{
-	float dist, invdist;
-
-	dist = point.Magnitude();
-	if (dist > 1.0f) {
-		invdist = 1.0f / dist;
-		point.x *= invdist;
-		point.y *= invdist;
-	}
-	return dist;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::LoadAllRadarBlips(int32) { EAXJMP(0x4A6F30); }
-#else
-void CRadar::LoadAllRadarBlips(uint8 *buf, uint32 size)
-{
-	Initialise();
-INITSAVEBUF
-	CheckSaveHeader(buf, 'R', 'D', 'R', '\0', size - SAVE_HEADER_SIZE);
-
-	for (int i = 0; i < NUMRADARBLIPS; i++)
-		ms_RadarTrace[i] = ReadSaveBuf<CBlip>(buf);
+		gRadarTxdIds[i] = CTxdStore::FindTxdSlot(gRadarTexNames[i]);
+}
+#endif
 
-VALIDATESAVEBUF(size);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::LoadTextures() { EAXJMP(0x4A4030); }
-#else
-void
-CRadar::LoadTextures()
-{
+#if 0
+WRAPPER float CRadar::LimitRadarPoint(CVector2D &point) { EAXJMP(0x4A4F30); }
+#else
+float CRadar::LimitRadarPoint(CVector2D &point)
+{
+	float dist, invdist;
+
+	dist = point.Magnitude();
+	if (dist > 1.0f) {
+		invdist = 1.0f / dist;
+		point.x *= invdist;
+		point.y *= invdist;
+	}
+	return dist;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::LoadAllRadarBlips(int32) { EAXJMP(0x4A6F30); }
+#else
+void CRadar::LoadAllRadarBlips(uint8 *buf, uint32 size)
+{
+	Initialise();
+INITSAVEBUF
+	CheckSaveHeader(buf, 'R', 'D', 'R', '\0', size - SAVE_HEADER_SIZE);
+
+	for (int i = 0; i < NUMRADARBLIPS; i++)
+		ms_RadarTrace[i] = ReadSaveBuf<CBlip>(buf);
+
+VALIDATESAVEBUF(size);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::LoadTextures() { EAXJMP(0x4A4030); }
+#else
+void
+CRadar::LoadTextures()
+{
 	CTxdStore::PushCurrentTxd();
 	CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("hud"));
 	AsukaSprite.SetTexture("radar_asuka");
@@ -957,210 +957,210 @@ CRadar::LoadTextures()
 	SpraySprite.SetTexture("radar_spray");
 	TonySprite.SetTexture("radar_tony");
 	WeaponSprite.SetTexture("radar_weapon");
-	CTxdStore::PopCurrentTxd();
-}
-#endif
-
-#if 0
-WRAPPER void RemoveMapSection(int32, int32) { EAXJMP(0x00); }
-#else
-void RemoveMapSection(int32 x, int32 y)
-{
-	if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
-		CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::RemoveRadarSections() { EAXJMP(0x4A60E0); }
-#else
-void CRadar::RemoveRadarSections()
-{
-	for (int i = 0; i < 8; i++)
+	CTxdStore::PopCurrentTxd();
+}
+#endif
+
+#if 0
+WRAPPER void RemoveMapSection(int32, int32) { EAXJMP(0x00); }
+#else
+void RemoveMapSection(int32 x, int32 y)
+{
+	if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
+		CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::RemoveRadarSections() { EAXJMP(0x4A60E0); }
+#else
+void CRadar::RemoveRadarSections()
+{
+	for (int i = 0; i < 8; i++)
 		for (int j = 0; j < 8; j++)
-			RemoveMapSection(i, j);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::RequestMapSection(int32, int32) { EAXJMP(0x00); }
-#else
-void CRadar::RequestMapSection(int32 x, int32 y)
-{
-	ClipRadarTileCoords(x, y);
-	CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::SaveAllRadarBlips(int32) { EAXJMP(0x4A6E30); }
-#else
-void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size)
-{
-	*size = SAVE_HEADER_SIZE + sizeof(ms_RadarTrace);
+			RemoveMapSection(i, j);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::RequestMapSection(int32, int32) { EAXJMP(0x00); }
+#else
+void CRadar::RequestMapSection(int32 x, int32 y)
+{
+	ClipRadarTileCoords(x, y);
+	CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size) { EAXJMP(0x4A6E30); }
+#else
+void CRadar::SaveAllRadarBlips(uint8 *buf, uint32 *size)
+{
+	*size = SAVE_HEADER_SIZE + sizeof(ms_RadarTrace);
 INITSAVEBUF
 	WriteSaveHeader(buf, 'R', 'D', 'R', '\0', *size - SAVE_HEADER_SIZE);
 
 	for (int i = 0; i < NUMRADARBLIPS; i++)
-		WriteSaveBuf(buf, ms_RadarTrace[i]);
-
-VALIDATESAVEBUF(*size);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::SetBlipSprite(int32, int32) { EAXJMP(0x4A5840); }
-#else
-void CRadar::SetBlipSprite(int32 i, int32 icon)
-{
-	int index = CRadar::GetActualBlipArrayIndex(i);
-	if (index != -1) {
-		ms_RadarTrace[index].m_IconID = icon;
-	}
-}
-#endif
-
-#if 0
-WRAPPER int32 CRadar::SetCoordBlip(eBlipType, CVector, int32, eBlipDisplay display) { EAXJMP(0x4A5590); }
-#else
-int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay display)
-{
-	int nextBlip;
-	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
-		if (!ms_RadarTrace[nextBlip].m_bInUse)
-			break;
-	}
-	ms_RadarTrace[nextBlip].m_eBlipType = type;
-	ms_RadarTrace[nextBlip].m_nColor = color;
-	ms_RadarTrace[nextBlip].m_bDim = 1;
-	ms_RadarTrace[nextBlip].m_bInUse = 1;
-	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
-	ms_RadarTrace[nextBlip].m_vec2DPos = pos;
-	ms_RadarTrace[nextBlip].m_vecPos = pos;
-	ms_RadarTrace[nextBlip].m_nEntityHandle = 0;
-	ms_RadarTrace[nextBlip].m_wScale = 1;
-	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
-	ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
-	return CRadar::GetNewUniqueBlipIndex(nextBlip);
-}
-#endif
-
-#if 0
-WRAPPER int CRadar::SetEntityBlip(eBlipType type, int32, int32, eBlipDisplay) { EAXJMP(0x4A5640); }
-#else
-int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDisplay display)
-{
-	int nextBlip;
-	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
-		if (!ms_RadarTrace[nextBlip].m_bInUse)
-			break;
-	}
-	ms_RadarTrace[nextBlip].m_eBlipType = type;
-	ms_RadarTrace[nextBlip].m_nColor = color;
-	ms_RadarTrace[nextBlip].m_bDim = 1;
-	ms_RadarTrace[nextBlip].m_bInUse = 1;
-	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
-	ms_RadarTrace[nextBlip].m_nEntityHandle = handle;
-	ms_RadarTrace[nextBlip].m_wScale = 1;
-	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
-	ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
-	return GetNewUniqueBlipIndex(nextBlip);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::SetRadarMarkerState(int32, bool) { EAXJMP(0x4A5C60); }
-#else
-void CRadar::SetRadarMarkerState(int32 counter, bool flag)
-{
-	CEntity *e;
-	switch (ms_RadarTrace[counter].m_eBlipType) {
-	case BLIP_CAR:
-		e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
-		break;
-	case BLIP_CHAR:
-		e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
-		break;
-	case BLIP_OBJECT:
-		e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
-		break;
-	default:
-		return;
-	}
-
-	if (e)
-		e->bHasBlip = flag;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) { EAXJMP(0x4A59C0); }
-#else
-void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) {
-	float f1 = radius * 1.4f;
-	float f2 = radius * 0.5f;
-	CVector p1, p2;
-
-	p1 = pos + TheCamera.GetUp()*f1;
-	p2 = pos + TheCamera.GetUp()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-
-	p1 = pos - TheCamera.GetUp()*f1;
-	p2 = pos - TheCamera.GetUp()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-
-	p1 = pos + TheCamera.GetRight()*f1;
-	p2 = pos + TheCamera.GetRight()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-
-	p1 = pos - TheCamera.GetRight()*f1;
-	p2 = pos - TheCamera.GetRight()*f2;
-	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha) { EAXJMP(0x4A5870); }
-#else
-void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha)
-{
-	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
-		return;
-
-	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
-	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
-}
-#endif
-
-void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint8 mode)
-{
-	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
-		return;
-
-	switch (mode)
-	{
-	case BLIP_MODE_TRIANGULAR_UP:
-		// size++; // VC does size + 1 for triangles
-		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 3.0f), y + SCREEN_SCALE_Y(size + 2.0f), x - (SCREEN_SCALE_X(size + 3.0f)), y + SCREEN_SCALE_Y(size + 2.0f), x, y - (SCREEN_SCALE_Y(size + 3.0f)), x, y - (SCREEN_SCALE_Y(size + 3.0f)), CRGBA(0, 0, 0, alpha));
-		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 1.0f), y + SCREEN_SCALE_Y(size + 1.0f), x - (SCREEN_SCALE_X(size + 1.0f)), y + SCREEN_SCALE_Y(size + 1.0f), x, y - (SCREEN_SCALE_Y(size + 1.0f)), x, y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
-		break;
-	case BLIP_MODE_TRIANGULAR_DOWN:
-		// size++; // VC does size + 1 for triangles
-		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 2.0f), x, y + SCREEN_SCALE_Y(size + 3.0f), x + SCREEN_SCALE_X(size + 3.0f), y - (SCREEN_SCALE_Y(size + 2.0f)), x - (SCREEN_SCALE_X(size + 3.0f)), y - (SCREEN_SCALE_Y(size + 2.0f)), CRGBA(0, 0, 0, alpha));
-		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 1.0f), x, y + SCREEN_SCALE_Y(size + 1.0f), x + SCREEN_SCALE_X(size + 1.0f), y - (SCREEN_SCALE_Y(size + 1.0f)), x - (SCREEN_SCALE_X(size + 1.0f)), y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
-		break;
-	case BLIP_MODE_SQUARE:
-		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
-		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
-		break;
-	}
-}
-
-#if 0
-WRAPPER void CRadar::Shutdown() { EAXJMP(0x4A3F60); }
-#else
-void CRadar::Shutdown()
-{
+		WriteSaveBuf(buf, ms_RadarTrace[i]);
+
+VALIDATESAVEBUF(*size);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SetBlipSprite(int32, int32) { EAXJMP(0x4A5840); }
+#else
+void CRadar::SetBlipSprite(int32 i, int32 icon)
+{
+	int index = CRadar::GetActualBlipArrayIndex(i);
+	if (index != -1) {
+		ms_RadarTrace[index].m_IconID = icon;
+	}
+}
+#endif
+
+#if 0
+WRAPPER int32 CRadar::SetCoordBlip(eBlipType, CVector, int32, eBlipDisplay display) { EAXJMP(0x4A5590); }
+#else
+int CRadar::SetCoordBlip(eBlipType type, CVector pos, int32 color, eBlipDisplay display)
+{
+	int nextBlip;
+	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
+		if (!ms_RadarTrace[nextBlip].m_bInUse)
+			break;
+	}
+	ms_RadarTrace[nextBlip].m_eBlipType = type;
+	ms_RadarTrace[nextBlip].m_nColor = color;
+	ms_RadarTrace[nextBlip].m_bDim = 1;
+	ms_RadarTrace[nextBlip].m_bInUse = 1;
+	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
+	ms_RadarTrace[nextBlip].m_vec2DPos = pos;
+	ms_RadarTrace[nextBlip].m_vecPos = pos;
+	ms_RadarTrace[nextBlip].m_nEntityHandle = 0;
+	ms_RadarTrace[nextBlip].m_wScale = 1;
+	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
+	ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
+	return CRadar::GetNewUniqueBlipIndex(nextBlip);
+}
+#endif
+
+#if 0
+WRAPPER int CRadar::SetEntityBlip(eBlipType type, int32, int32, eBlipDisplay) { EAXJMP(0x4A5640); }
+#else
+int CRadar::SetEntityBlip(eBlipType type, int32 handle, int32 color, eBlipDisplay display)
+{
+	int nextBlip;
+	for (nextBlip = 0; nextBlip < NUMRADARBLIPS; nextBlip++) {
+		if (!ms_RadarTrace[nextBlip].m_bInUse)
+			break;
+	}
+	ms_RadarTrace[nextBlip].m_eBlipType = type;
+	ms_RadarTrace[nextBlip].m_nColor = color;
+	ms_RadarTrace[nextBlip].m_bDim = 1;
+	ms_RadarTrace[nextBlip].m_bInUse = 1;
+	ms_RadarTrace[nextBlip].m_Radius = 1.0f;
+	ms_RadarTrace[nextBlip].m_nEntityHandle = handle;
+	ms_RadarTrace[nextBlip].m_wScale = 1;
+	ms_RadarTrace[nextBlip].m_eBlipDisplay = display;
+	ms_RadarTrace[nextBlip].m_IconID = RADAR_SPRITE_NONE;
+	return GetNewUniqueBlipIndex(nextBlip);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SetRadarMarkerState(int32, bool) { EAXJMP(0x4A5C60); }
+#else
+void CRadar::SetRadarMarkerState(int32 counter, bool flag)
+{
+	CEntity *e;
+	switch (ms_RadarTrace[counter].m_eBlipType) {
+	case BLIP_CAR:
+		e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+		break;
+	case BLIP_CHAR:
+		e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+		break;
+	case BLIP_OBJECT:
+		e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+		break;
+	default:
+		return;
+	}
+
+	if (e)
+		e->bHasBlip = flag;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) { EAXJMP(0x4A59C0); }
+#else
+void CRadar::ShowRadarMarker(CVector pos, uint32 color, float radius) {
+	float f1 = radius * 1.4f;
+	float f2 = radius * 0.5f;
+	CVector p1, p2;
+
+	p1 = pos + TheCamera.GetUp()*f1;
+	p2 = pos + TheCamera.GetUp()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+	p1 = pos - TheCamera.GetUp()*f1;
+	p2 = pos - TheCamera.GetUp()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+	p1 = pos + TheCamera.GetRight()*f1;
+	p2 = pos + TheCamera.GetRight()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+	p1 = pos - TheCamera.GetRight()*f1;
+	p2 = pos - TheCamera.GetRight()*f2;
+	CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha) { EAXJMP(0x4A5870); }
+#else
+void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha)
+{
+	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
+		return;
+
+	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
+	CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
+}
+#endif
+
+void CRadar::ShowRadarTraceWithHeight(float x, float y, uint32 size, uint8 red, uint8 green, uint8 blue, uint8 alpha, uint8 mode)
+{
+	if (!CHud::m_Wants_To_Draw_Hud || TheCamera.m_WideScreenOn)
+		return;
+
+	switch (mode)
+	{
+	case BLIP_MODE_TRIANGULAR_UP:
+		// size++; // VC does size + 1 for triangles
+		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 3.0f), y + SCREEN_SCALE_Y(size + 2.0f), x - (SCREEN_SCALE_X(size + 3.0f)), y + SCREEN_SCALE_Y(size + 2.0f), x, y - (SCREEN_SCALE_Y(size + 3.0f)), x, y - (SCREEN_SCALE_Y(size + 3.0f)), CRGBA(0, 0, 0, alpha));
+		CSprite2d::Draw2DPolygon(x + SCREEN_SCALE_X(size + 1.0f), y + SCREEN_SCALE_Y(size + 1.0f), x - (SCREEN_SCALE_X(size + 1.0f)), y + SCREEN_SCALE_Y(size + 1.0f), x, y - (SCREEN_SCALE_Y(size + 1.0f)), x, y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
+		break;
+	case BLIP_MODE_TRIANGULAR_DOWN:
+		// size++; // VC does size + 1 for triangles
+		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 2.0f), x, y + SCREEN_SCALE_Y(size + 3.0f), x + SCREEN_SCALE_X(size + 3.0f), y - (SCREEN_SCALE_Y(size + 2.0f)), x - (SCREEN_SCALE_X(size + 3.0f)), y - (SCREEN_SCALE_Y(size + 2.0f)), CRGBA(0, 0, 0, alpha));
+		CSprite2d::Draw2DPolygon(x, y + SCREEN_SCALE_Y(size + 1.0f), x, y + SCREEN_SCALE_Y(size + 1.0f), x + SCREEN_SCALE_X(size + 1.0f), y - (SCREEN_SCALE_Y(size + 1.0f)), x - (SCREEN_SCALE_X(size + 1.0f)), y - (SCREEN_SCALE_Y(size + 1.0f)), CRGBA(red, green, blue, alpha));
+		break;
+	case BLIP_MODE_SQUARE:
+		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
+		CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
+		break;
+	}
+}
+
+#if 0
+WRAPPER void CRadar::Shutdown() { EAXJMP(0x4A3F60); }
+#else
+void CRadar::Shutdown()
+{
 	AsukaSprite.Delete();
 	BombSprite.Delete();
 	CatSprite.Delete();
@@ -1181,298 +1181,298 @@ void CRadar::Shutdown()
 	SpraySprite.Delete();
 	TonySprite.Delete();
 	WeaponSprite.Delete();
-	RemoveRadarSections();
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::StreamRadarSections(const CVector &posn) { EAXJMP(0x4A6B60); }
-#else
-void CRadar::StreamRadarSections(const CVector &posn)
+	RemoveRadarSections();
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::StreamRadarSections(const CVector &posn) { EAXJMP(0x4A6B60); }
+#else
+void CRadar::StreamRadarSections(const CVector &posn)
 {
-	StreamRadarSections(floorf((2000.0f + posn.x) / 500.0f), ceilf(7.0f - (2000.0f + posn.y) / 500.0f));
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::StreamRadarSections(int32 x, int32 y) { EAXJMP(0x4A6100); }
-#else
-void CRadar::StreamRadarSections(int32 x, int32 y)
-{
-	for (int i = 0; i < RADAR_NUM_TILES; ++i) {
-		for (int j = 0; j < RADAR_NUM_TILES; ++j) {
-			if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1))
-				RequestMapSection(i, j);
-			else
-				RemoveMapSection(i, j);
-		};
-	};
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) { EAXJMP(0x4A5530); }
-#else
-void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y)
-{
-	out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X);
-	out.y = -(in.y - ((RADAR_NUM_TILES - y) * RADAR_TILE_SIZE + WORLD_MIN_Y));
-	out.x /= RADAR_TILE_SIZE;
-	out.y /= RADAR_TILE_SIZE;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A5300); }
-#else
-void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
-{
-	float s, c;
-
-	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());
-	}
-
-	out.x = s * in.y + c * in.x;
-	out.y = c * in.y - s * in.x;
-
-	out = out * m_radarRange + vec2DRadarOrigin;
-}
-#endif
-
-// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0)
-void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in)
-{
-	// FIX? scale RADAR_LEFT here somehow
-	out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT;
-	out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT);
-}
-
-#if 0
-WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A50D0); }
-#else
-void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
-{
-	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());
-	}
-
-	float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_radarRange);
-	float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_radarRange);
-
-	out.x = s * y + c * x;
-	out.y = c * y - s * x;
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) { EAXJMP(0x4A61C0); };
-#else
-// Transform from section indices to world coordinates
-void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out)
-{
-	x =   x - RADAR_NUM_TILES/2;
-	y = -(y - RADAR_NUM_TILES/2);
-
-	// bottom left
-	out[0].x = RADAR_TILE_SIZE * (x);
-	out[0].y = RADAR_TILE_SIZE * (y - 1);
-
-	// bottom right
-	out[1].x = RADAR_TILE_SIZE * (x + 1);
-	out[1].y = RADAR_TILE_SIZE * (y - 1);
-
-	// top right
-	out[2].x = RADAR_TILE_SIZE * (x + 1);
-	out[2].y = RADAR_TILE_SIZE * (y);
-
-	// top left
-	out[3].x = RADAR_TILE_SIZE * (x);
-	out[3].y = RADAR_TILE_SIZE * (y);
-}
-#endif
-
-#if 0
-WRAPPER void CRadar::ClipRadarTileCoords(int32 &, int32 &) { EAXJMP(0x00); };
-#else
-void CRadar::ClipRadarTileCoords(int32 &x, int32 &y)
-{
-	if (x < 0)
-		x = 0;
-	if (x > RADAR_NUM_TILES-1)
-		x = RADAR_NUM_TILES-1;
-	if (y < 0)
-		y = 0;
-	if (y > RADAR_NUM_TILES-1)
-		y = RADAR_NUM_TILES-1;
-}
-#endif
-
-
-#if 0
-WRAPPER bool CRadar::IsPointInsideRadar(const CVector2D &) { EAXJMP(0x4A6160); }
-#else
-bool CRadar::IsPointInsideRadar(const CVector2D &point)
-{
-	if (point.x < -1.0f || point.x > 1.0f) return false;
-	if (point.y < -1.0f || point.y > 1.0f) return false;
-	return true;
-}
-#endif
-
-// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1
-#if 0
-WRAPPER int CRadar::LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &) { EAXJMP(0x4A6250); }
-#else
-int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2)
-{
-	float d1, d2;
-	float t;
-	float x, y;
-	float shortest = 1.0f;
-	int edge = -1;
-
-	// clip against left edge, x = -1.0
-	d1 = -1.0f - p1.x;
-	d2 = -1.0f - p2.x;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		y = (p2.y - p1.y)*t + p1.y;
-		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
-			out.x = -1.0f;
-			out.y = y;
-			edge = 3;
-			shortest = t;
-		}
-	}
-
-	// clip against right edge, x = 1.0
-	d1 = p1.x - 1.0f;
-	d2 = p2.x - 1.0f;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		y = (p2.y - p1.y)*t + p1.y;
-		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
-			out.x = 1.0f;
-			out.y = y;
-			edge = 1;
-			shortest = t;
-		}
-	}
-
-	// clip against top edge, y = -1.0
-	d1 = -1.0f - p1.y;
-	d2 = -1.0f - p2.y;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		x = (p2.x - p1.x)*t + p1.x;
-		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
-			out.y = -1.0f;
-			out.x = x;
-			edge = 0;
-			shortest = t;
-		}
-	}
-
-	// clip against bottom edge, y = 1.0
-	d1 = p1.y - 1.0f;
-	d2 = p2.y - 1.0f;
-	if (d1 * d2 < 0.0f) {
-		// they are on opposite sides, get point of intersection
-		t = d1 / (d1 - d2);
-		x = (p2.x - p1.x)*t + p1.x;
-		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
-			out.y = 1.0f;
-			out.x = x;
-			edge = 2;
-			shortest = t;
-		}
-	}
-
-	return edge;
-}
-#endif
-
-STARTPATCHES
-	InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP);
-	InjectHook(0x4A3F60, CRadar::Shutdown, PATCH_JUMP);
-	InjectHook(0x4A4030, CRadar::LoadTextures, PATCH_JUMP);
-	InjectHook(0x4A4180, CRadar::GetNewUniqueBlipIndex, PATCH_JUMP);
-	InjectHook(0x4A41C0, CRadar::GetActualBlipArrayIndex, PATCH_JUMP);
-	InjectHook(0x4A4200, CRadar::DrawMap, PATCH_JUMP);
-	InjectHook(0x4A42F0, CRadar::DrawBlips, PATCH_JUMP);
-	InjectHook(0x4A4C70, CRadar::Draw3dMarkers, PATCH_JUMP);
-	InjectHook(0x4A4F30, CRadar::LimitRadarPoint, PATCH_JUMP);
-	InjectHook(0x4A4F90, CRadar::CalculateBlipAlpha, PATCH_JUMP);
-	InjectHook(0x4A5040, CRadar::TransformRadarPointToScreenSpace, PATCH_JUMP);
-	InjectHook(0x4A50D0, CRadar::TransformRealWorldPointToRadarSpace, PATCH_JUMP);
-	InjectHook(0x4A5300, CRadar::TransformRadarPointToRealWorldSpace, PATCH_JUMP);
-	InjectHook(0x4A5530, CRadar::TransformRealWorldToTexCoordSpace, PATCH_JUMP);
-	InjectHook(0x4A5590, CRadar::SetCoordBlip, PATCH_JUMP);
-	InjectHook(0x4A5640, CRadar::SetEntityBlip, PATCH_JUMP);
-	InjectHook(0x4A56C0, CRadar::ClearBlipForEntity, PATCH_JUMP);
-	InjectHook(0x4A5720, CRadar::ClearBlip, PATCH_JUMP);
-	InjectHook(0x4A5770, CRadar::ChangeBlipColour, PATCH_JUMP);
-	InjectHook(0x4A57A0, CRadar::ChangeBlipBrightness, PATCH_JUMP);
-	InjectHook(0x4A57E0, CRadar::ChangeBlipScale, PATCH_JUMP);
-	InjectHook(0x4A5810, CRadar::ChangeBlipDisplay, PATCH_JUMP);
-	InjectHook(0x4A5840, CRadar::SetBlipSprite, PATCH_JUMP);
-	InjectHook(0x4A5870, CRadar::ShowRadarTrace, PATCH_JUMP);
-	InjectHook(0x4A59C0, CRadar::ShowRadarMarker, PATCH_JUMP);
-	InjectHook(0x4A5BB0, CRadar::GetRadarTraceColour, PATCH_JUMP);
-	InjectHook(0x4A5C60, CRadar::SetRadarMarkerState, PATCH_JUMP);
-	InjectHook(0x4A5D10, CRadar::DrawRotatingRadarSprite, PATCH_JUMP);
-	InjectHook(0x4A5EF0, CRadar::DrawRadarSprite, PATCH_JUMP);
-	InjectHook(0x4A60E0, CRadar::RemoveRadarSections, PATCH_JUMP);
-	InjectHook(0x4A6100, (void (*)(int32, int32))&CRadar::StreamRadarSections, PATCH_JUMP);
-	InjectHook(0x4A64A0, CRadar::ClipRadarPoly, PATCH_JUMP);
-	InjectHook(0x4A67E0, CRadar::DrawRadarSection, PATCH_JUMP);
-	InjectHook(0x4A69C0, CRadar::DrawRadarMask, PATCH_JUMP);
-	InjectHook(0x4A6B60, (void (*)(const CVector&))&CRadar::StreamRadarSections, PATCH_JUMP);
-	InjectHook(0x4A6C20, CRadar::DrawRadarMap, PATCH_JUMP);
-	InjectHook(0x4A6E30, CRadar::SaveAllRadarBlips, PATCH_JUMP);
-	InjectHook(0x4A6F30, CRadar::LoadAllRadarBlips, PATCH_JUMP);
-
-	InjectHook(0x4A61C0, CRadar::GetTextureCorners, PATCH_JUMP);
-	InjectHook(0x4A6160, CRadar::IsPointInsideRadar, PATCH_JUMP);
-	InjectHook(0x4A6250, CRadar::LineRadarBoxCollision, PATCH_JUMP);
-ENDPATCHES
+	StreamRadarSections(floorf((2000.0f + posn.x) / 500.0f), ceilf(7.0f - (2000.0f + posn.y) / 500.0f));
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::StreamRadarSections(int32 x, int32 y) { EAXJMP(0x4A6100); }
+#else
+void CRadar::StreamRadarSections(int32 x, int32 y)
+{
+	for (int i = 0; i < RADAR_NUM_TILES; ++i) {
+		for (int j = 0; j < RADAR_NUM_TILES; ++j) {
+			if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1))
+				RequestMapSection(i, j);
+			else
+				RemoveMapSection(i, j);
+		};
+	};
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) { EAXJMP(0x4A5530); }
+#else
+void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y)
+{
+	out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X);
+	out.y = -(in.y - ((RADAR_NUM_TILES - y) * RADAR_TILE_SIZE + WORLD_MIN_Y));
+	out.x /= RADAR_TILE_SIZE;
+	out.y /= RADAR_TILE_SIZE;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A5300); }
+#else
+void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
+{
+	float s, c;
+
+	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());
+	}
+
+	out.x = s * in.y + c * in.x;
+	out.y = c * in.y - s * in.x;
+
+	out = out * m_radarRange + vec2DRadarOrigin;
+}
+#endif
+
+// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0)
+void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in)
+{
+	// FIX? scale RADAR_LEFT here somehow
+	out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT;
+	out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT);
+}
+
+#if 0
+WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A50D0); }
+#else
+void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
+{
+	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());
+	}
+
+	float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_radarRange);
+	float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_radarRange);
+
+	out.x = s * y + c * x;
+	out.y = c * y - s * x;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) { EAXJMP(0x4A61C0); };
+#else
+// Transform from section indices to world coordinates
+void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out)
+{
+	x =   x - RADAR_NUM_TILES/2;
+	y = -(y - RADAR_NUM_TILES/2);
+
+	// bottom left
+	out[0].x = RADAR_TILE_SIZE * (x);
+	out[0].y = RADAR_TILE_SIZE * (y - 1);
+
+	// bottom right
+	out[1].x = RADAR_TILE_SIZE * (x + 1);
+	out[1].y = RADAR_TILE_SIZE * (y - 1);
+
+	// top right
+	out[2].x = RADAR_TILE_SIZE * (x + 1);
+	out[2].y = RADAR_TILE_SIZE * (y);
+
+	// top left
+	out[3].x = RADAR_TILE_SIZE * (x);
+	out[3].y = RADAR_TILE_SIZE * (y);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ClipRadarTileCoords(int32 &, int32 &) { EAXJMP(0x00); };
+#else
+void CRadar::ClipRadarTileCoords(int32 &x, int32 &y)
+{
+	if (x < 0)
+		x = 0;
+	if (x > RADAR_NUM_TILES-1)
+		x = RADAR_NUM_TILES-1;
+	if (y < 0)
+		y = 0;
+	if (y > RADAR_NUM_TILES-1)
+		y = RADAR_NUM_TILES-1;
+}
+#endif
+
+
+#if 0
+WRAPPER bool CRadar::IsPointInsideRadar(const CVector2D &) { EAXJMP(0x4A6160); }
+#else
+bool CRadar::IsPointInsideRadar(const CVector2D &point)
+{
+	if (point.x < -1.0f || point.x > 1.0f) return false;
+	if (point.y < -1.0f || point.y > 1.0f) return false;
+	return true;
+}
+#endif
+
+// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1
+#if 0
+WRAPPER int CRadar::LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &) { EAXJMP(0x4A6250); }
+#else
+int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2)
+{
+	float d1, d2;
+	float t;
+	float x, y;
+	float shortest = 1.0f;
+	int edge = -1;
+
+	// clip against left edge, x = -1.0
+	d1 = -1.0f - p1.x;
+	d2 = -1.0f - p2.x;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		y = (p2.y - p1.y)*t + p1.y;
+		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
+			out.x = -1.0f;
+			out.y = y;
+			edge = 3;
+			shortest = t;
+		}
+	}
+
+	// clip against right edge, x = 1.0
+	d1 = p1.x - 1.0f;
+	d2 = p2.x - 1.0f;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		y = (p2.y - p1.y)*t + p1.y;
+		if (y >= -1.0f && y <= 1.0f && t <= shortest) {
+			out.x = 1.0f;
+			out.y = y;
+			edge = 1;
+			shortest = t;
+		}
+	}
+
+	// clip against top edge, y = -1.0
+	d1 = -1.0f - p1.y;
+	d2 = -1.0f - p2.y;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		x = (p2.x - p1.x)*t + p1.x;
+		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
+			out.y = -1.0f;
+			out.x = x;
+			edge = 0;
+			shortest = t;
+		}
+	}
+
+	// clip against bottom edge, y = 1.0
+	d1 = p1.y - 1.0f;
+	d2 = p2.y - 1.0f;
+	if (d1 * d2 < 0.0f) {
+		// they are on opposite sides, get point of intersection
+		t = d1 / (d1 - d2);
+		x = (p2.x - p1.x)*t + p1.x;
+		if (x >= -1.0f && x <= 1.0f && t <= shortest) {
+			out.y = 1.0f;
+			out.x = x;
+			edge = 2;
+			shortest = t;
+		}
+	}
+
+	return edge;
+}
+#endif
+
+STARTPATCHES
+	InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP);
+	InjectHook(0x4A3F60, CRadar::Shutdown, PATCH_JUMP);
+	InjectHook(0x4A4030, CRadar::LoadTextures, PATCH_JUMP);
+	InjectHook(0x4A4180, CRadar::GetNewUniqueBlipIndex, PATCH_JUMP);
+	InjectHook(0x4A41C0, CRadar::GetActualBlipArrayIndex, PATCH_JUMP);
+	InjectHook(0x4A4200, CRadar::DrawMap, PATCH_JUMP);
+	InjectHook(0x4A42F0, CRadar::DrawBlips, PATCH_JUMP);
+	InjectHook(0x4A4C70, CRadar::Draw3dMarkers, PATCH_JUMP);
+	InjectHook(0x4A4F30, CRadar::LimitRadarPoint, PATCH_JUMP);
+	InjectHook(0x4A4F90, CRadar::CalculateBlipAlpha, PATCH_JUMP);
+	InjectHook(0x4A5040, CRadar::TransformRadarPointToScreenSpace, PATCH_JUMP);
+	InjectHook(0x4A50D0, CRadar::TransformRealWorldPointToRadarSpace, PATCH_JUMP);
+	InjectHook(0x4A5300, CRadar::TransformRadarPointToRealWorldSpace, PATCH_JUMP);
+	InjectHook(0x4A5530, CRadar::TransformRealWorldToTexCoordSpace, PATCH_JUMP);
+	InjectHook(0x4A5590, CRadar::SetCoordBlip, PATCH_JUMP);
+	InjectHook(0x4A5640, CRadar::SetEntityBlip, PATCH_JUMP);
+	InjectHook(0x4A56C0, CRadar::ClearBlipForEntity, PATCH_JUMP);
+	InjectHook(0x4A5720, CRadar::ClearBlip, PATCH_JUMP);
+	InjectHook(0x4A5770, CRadar::ChangeBlipColour, PATCH_JUMP);
+	InjectHook(0x4A57A0, CRadar::ChangeBlipBrightness, PATCH_JUMP);
+	InjectHook(0x4A57E0, CRadar::ChangeBlipScale, PATCH_JUMP);
+	InjectHook(0x4A5810, CRadar::ChangeBlipDisplay, PATCH_JUMP);
+	InjectHook(0x4A5840, CRadar::SetBlipSprite, PATCH_JUMP);
+	InjectHook(0x4A5870, CRadar::ShowRadarTrace, PATCH_JUMP);
+	InjectHook(0x4A59C0, CRadar::ShowRadarMarker, PATCH_JUMP);
+	InjectHook(0x4A5BB0, CRadar::GetRadarTraceColour, PATCH_JUMP);
+	InjectHook(0x4A5C60, CRadar::SetRadarMarkerState, PATCH_JUMP);
+	InjectHook(0x4A5D10, CRadar::DrawRotatingRadarSprite, PATCH_JUMP);
+	InjectHook(0x4A5EF0, CRadar::DrawRadarSprite, PATCH_JUMP);
+	InjectHook(0x4A60E0, CRadar::RemoveRadarSections, PATCH_JUMP);
+	InjectHook(0x4A6100, (void (*)(int32, int32))&CRadar::StreamRadarSections, PATCH_JUMP);
+	InjectHook(0x4A64A0, CRadar::ClipRadarPoly, PATCH_JUMP);
+	InjectHook(0x4A67E0, CRadar::DrawRadarSection, PATCH_JUMP);
+	InjectHook(0x4A69C0, CRadar::DrawRadarMask, PATCH_JUMP);
+	InjectHook(0x4A6B60, (void (*)(const CVector&))&CRadar::StreamRadarSections, PATCH_JUMP);
+	InjectHook(0x4A6C20, CRadar::DrawRadarMap, PATCH_JUMP);
+	InjectHook(0x4A6E30, CRadar::SaveAllRadarBlips, PATCH_JUMP);
+	InjectHook(0x4A6F30, CRadar::LoadAllRadarBlips, PATCH_JUMP);
+
+	InjectHook(0x4A61C0, CRadar::GetTextureCorners, PATCH_JUMP);
+	InjectHook(0x4A6160, CRadar::IsPointInsideRadar, PATCH_JUMP);
+	InjectHook(0x4A6250, CRadar::LineRadarBoxCollision, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp
index 2c27ba70..1d088e04 100644
--- a/src/core/Stats.cpp
+++ b/src/core/Stats.cpp
@@ -1,6 +1,9 @@
 #include "common.h"
+#include "patcher.h"
 #include "Stats.h"
 
+WRAPPER void CStats::SaveStats(uint8 *buf, uint32 *size) { EAXJMP(0x4ab3e0); }
+
 int32 &CStats::DaysPassed = *(int32*)0x8F2BB8;
 int32 &CStats::HeadsPopped = *(int32*)0x8F647C;
 bool& CStats::CommercialPassed = *(bool*)0x8F4334;
diff --git a/src/core/Stats.h b/src/core/Stats.h
index 4b558c32..4bf99c45 100644
--- a/src/core/Stats.h
+++ b/src/core/Stats.h
@@ -73,4 +73,5 @@ public:
 	static void CheckPointReachedUnsuccessfully() { KillsSinceLastCheckpoint = 0; };
 	static void CheckPointReachedSuccessfully() { TotalLegitimateKills += KillsSinceLastCheckpoint; KillsSinceLastCheckpoint = 0; };
 	static void RegisterElBurroTime(int32);
-};
\ No newline at end of file
+	static void SaveStats(uint8 *buf, uint32 *size);
+};
diff --git a/src/core/TimeStep.cpp b/src/core/TimeStep.cpp
new file mode 100644
index 00000000..9ccf7200
--- /dev/null
+++ b/src/core/TimeStep.cpp
@@ -0,0 +1,5 @@
+#include "TimeStep.h"
+
+float &CTimeStep::ms_fTimeScale = *(float*)0x5F76C8;
+float &CTimeStep::ms_fFramesPerUpdate = *(float*)0x5F76CC;
+float &CTimeStep::ms_fTimeStep = *(float*)0x5F76D0;
diff --git a/src/core/TimeStep.h b/src/core/TimeStep.h
new file mode 100644
index 00000000..c74df02a
--- /dev/null
+++ b/src/core/TimeStep.h
@@ -0,0 +1,10 @@
+#pragma once
+
+// Pretty sure this class is not used by the game
+class CTimeStep
+{
+public:
+	static float &ms_fTimeScale;
+	static float &ms_fFramesPerUpdate;
+	static float &ms_fTimeStep;
+};
diff --git a/src/core/Timer.h b/src/core/Timer.h
index 8f3b77c2..89c4a430 100644
--- a/src/core/Timer.h
+++ b/src/core/Timer.h
@@ -2,6 +2,7 @@
 
 class CTimer
 {
+public:
 	static uint32 &m_snTimeInMilliseconds;
 	static uint32 &m_snTimeInMillisecondsPauseMode;
 	static uint32 &m_snTimeInMillisecondsNonClipped;
@@ -12,7 +13,7 @@ class CTimer
 	static float &ms_fTimeStepNonClipped;
 	static bool  &m_UserPause;
 	static bool  &m_CodePause;
-public:
+
 	static float GetTimeStep(void) { return ms_fTimeStep; }
 	static void SetTimeStep(float ts) { ms_fTimeStep = ts; }
 	static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; }
diff --git a/src/core/common.h b/src/core/common.h
index cadcac1d..9a5cdb38 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -321,9 +321,9 @@ _TWEEKCLASS(CTweakFloat, float);
 #undef _TWEEKCLASS
 
 #ifdef VALIDATE_SAVE_SIZE
-extern int32 _bufBytesRead;
-#define INITSAVEBUF _bufBytesRead = 0;
-#define VALIDATESAVEBUF(b) assert(_bufBytesRead == b);
+extern int32 _saveBufCount;
+#define INITSAVEBUF _saveBufCount = 0;
+#define VALIDATESAVEBUF(b) assert(_saveBufCount == b);
 #else
 #define INITSAVEBUF
 #define VALIDATESAVEBUF(b)
@@ -333,7 +333,7 @@ inline void SkipSaveBuf(uint8 *&buf, int32 skip)
 {
 	buf += skip;
 #ifdef VALIDATE_SAVE_SIZE
-	_bufBytesRead += skip;
+	_saveBufCount += skip;
 #endif
 }
 
diff --git a/src/core/config.h b/src/core/config.h
index faad34b9..03b8a019 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -168,6 +168,10 @@ enum Config {
 #define USE_MEASUREMENTS_IN_METERS // makes game use meters instead of feet in script
 #define USE_PRECISE_MEASUREMENT_CONVERTION // makes game convert feet to meeters more precisely
 
+// Replay
+//#define DONT_FIX_REPLAY_BUGS // keeps various bugs in CReplay, some of which are fairly cool!
+//#define USE_BETA_REPLAY_MODE // adds another replay mode, a few seconds slomo (caution: buggy!)
+
 // Vehicles
 #define EXPLODING_AIRTRAIN	// can blow up jumbo jet with rocket launcher
 //#define REMOVE_TREADABLE_PATHFIND
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 989a05b5..ed32632f 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -449,7 +449,7 @@ void re3_trace(const char *filename, unsigned int lineno, const char *func, cons
 }
 
 #ifdef VALIDATE_SAVE_SIZE
-int32 _bufBytesRead;
+int32 _saveBufCount;
 #endif
 
 void
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index 5a55dbd5..8c851686 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -1,21 +1,40 @@
 #include "common.h"
 #include "main.h"
 #include "patcher.h"
+#include "AudioScriptObject.h"
 #include "Camera.h"
+#include "CarGen.h"
+#include "Cranes.h"
 #include "Clock.h"
 #include "Date.h"
 #include "FileMgr.h"
 #include "GameLogic.h"
+#include "Gangs.h"
 #include "Garages.h"
 #include "GenericGameStorage.h"
+#include "Pad.h"
+#include "ParticleObject.h"
+#include "PathFind.h"
 #include "PCSave.h"
+#include "Phones.h"
+#include "Pickups.h"
 #include "PlayerPed.h"
 #include "Pools.h"
+#include "Radar.h"
+#include "Restart.h"
 #include "Script.h"
+#include "Stats.h"
 #include "Streaming.h"
+#include "Timer.h"
+#include "TimeStep.h"
+#include "Weather.h"
 #include "World.h"
+#include "Zones.h"
 
-const int SIZE_OF_ONE_GAME_IN_BYTES = 201729;
+#define BLOCK_COUNT 20
+#define SIZE_OF_SIMPLEVARS 0xBC
+
+const uint32 SIZE_OF_ONE_GAME_IN_BYTES = 201729;
 
 char (&DefaultPCSaveFileName)[260] = *(char(*)[260])*(uintptr*)0x8E28C0;
 char (&ValidSaveName)[260] = *(char(*)[260])*(uintptr*)0x8E2CBC;
@@ -31,9 +50,152 @@ CDate &CompileDateAndTime = *(CDate*)0x72BCB8;
 #define ReadDataFromBufferPointer(buf, to) memcpy(&to, buf, sizeof(to)); buf += align4bytes(sizeof(to));
 #define WriteDataToBufferPointer(buf, from) memcpy(buf, &from, sizeof(from)); buf += align4bytes(sizeof(from));
 
-WRAPPER bool GenericSave(int file) { EAXJMP(0x58F8D0); }
+//WRAPPER bool GenericSave(int file) { EAXJMP(0x58F8D0); }
 WRAPPER bool GenericLoad() { EAXJMP(0x590A00); }
 
+
+#define WRITE_BLOCK(save_func)\
+do {\
+	buf = work_buff;\
+	reserved = 0;\
+	MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\
+	save_func(buf, &size);\
+	CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\
+	if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + 4))\
+		return false;\
+	totalSize += size;\
+} while (0)
+
+bool
+GenericSave(int file)
+{
+	uint8 *buf, *presize, *postsize;
+	uint32 size;
+	uint32 reserved;
+
+	uint32 totalSize;
+	uint32 i;
+	
+	wchar *lastMissionPassed;
+	wchar suffix[6];
+	wchar saveName[24];
+	SYSTEMTIME saveTime;
+	CPad *currPad;
+
+	CheckSum = 0;
+	buf = work_buff;
+	reserved = 0;
+	totalSize = 0;
+
+	// Save simple vars
+INITSAVEBUF
+	lastMissionPassed = TheText.Get(CStats::LastMissionPassedName);
+	if (*lastMissionPassed) {
+		AsciiToUnicode("'...", suffix);
+		TextCopy(saveName, lastMissionPassed);
+		int len = UnicodeStrlen(saveName);
+		saveName[len] = '\0';
+		if (len > 22)
+			TextCopy(saveName + 18, suffix);
+		saveName[23] = '\0';
+	}
+	WriteDataToBufferPointer(buf, saveName);
+	GetLocalTime(&saveTime);
+	WriteDataToBufferPointer(buf, saveTime);
+	WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES);
+	WriteDataToBufferPointer(buf, CGame::currLevel);
+	WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.x);
+	WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.y);
+	WriteDataToBufferPointer(buf, TheCamera.m_matrix.m_matrix.pos.z);
+	WriteDataToBufferPointer(buf, CClock::ms_nMillisecondsPerGameMinute);
+	WriteDataToBufferPointer(buf, CClock::ms_nLastClockTick);
+	WriteDataToBufferPointer(buf, CClock::ms_nGameClockHours);
+	WriteDataToBufferPointer(buf, CClock::ms_nGameClockMinutes);
+	currPad = CPad::GetPad(0);
+	WriteDataToBufferPointer(buf, currPad->Mode);
+	WriteDataToBufferPointer(buf, CTimer::m_snTimeInMilliseconds);
+	WriteDataToBufferPointer(buf, CTimer::ms_fTimeScale);
+	WriteDataToBufferPointer(buf, CTimer::ms_fTimeStep);
+	WriteDataToBufferPointer(buf, CTimer::ms_fTimeStepNonClipped);
+	WriteDataToBufferPointer(buf, CTimer::m_FrameCounter);
+	WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeStep);
+	WriteDataToBufferPointer(buf, CTimeStep::ms_fFramesPerUpdate);
+	WriteDataToBufferPointer(buf, CTimeStep::ms_fTimeScale);
+	WriteDataToBufferPointer(buf, CWeather::OldWeatherType);
+	WriteDataToBufferPointer(buf, CWeather::NewWeatherType);
+	WriteDataToBufferPointer(buf, CWeather::ForcedWeatherType);
+	WriteDataToBufferPointer(buf, CWeather::InterpolationValue);
+	WriteDataToBufferPointer(buf, CompileDateAndTime.m_nSecond);
+	WriteDataToBufferPointer(buf, CompileDateAndTime.m_nMinute);
+	WriteDataToBufferPointer(buf, CompileDateAndTime.m_nHour);
+	WriteDataToBufferPointer(buf, CompileDateAndTime.m_nDay);
+	WriteDataToBufferPointer(buf, CompileDateAndTime.m_nMonth);
+	WriteDataToBufferPointer(buf, CompileDateAndTime.m_nYear);
+	WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList);
+	WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator);
+	WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator);
+#ifdef VALIDATE_SAVE_SIZE
+	_saveBufCount = buf - work_buff;
+#endif
+VALIDATESAVEBUF(SIZE_OF_SIMPLEVARS);
+
+	// Save scripts, block is nested within the same block as simple vars for some reason
+	presize = buf;
+	buf += 4;
+	postsize = buf;
+	CTheScripts::SaveAllScripts(buf, &size);
+	CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);
+	if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size + SIZE_OF_SIMPLEVARS + 4))
+		return false;
+	totalSize += size + SIZE_OF_SIMPLEVARS;
+
+	// Save the rest
+	WRITE_BLOCK(CPools::SavePedPool);
+	WRITE_BLOCK(CGarages::Save);
+	WRITE_BLOCK(CPools::SaveVehiclePool);
+	WRITE_BLOCK(CPools::SaveObjectPool);
+	WRITE_BLOCK(ThePaths.Save);
+	WRITE_BLOCK(CCranes::Save);
+	WRITE_BLOCK(CPickups::Save);
+	WRITE_BLOCK(gPhoneInfo.Save);
+	WRITE_BLOCK(CRestart::SaveAllRestartPoints);
+	WRITE_BLOCK(CRadar::SaveAllRadarBlips);
+	WRITE_BLOCK(CTheZones::SaveAllZones);
+	WRITE_BLOCK(CGangs::SaveAllGangData);
+	WRITE_BLOCK(CTheCarGenerators::SaveAllCarGenerators);
+	WRITE_BLOCK(CParticleObject::SaveParticle);
+	WRITE_BLOCK(cAudioScriptObject::SaveAllAudioScriptObjects);
+	WRITE_BLOCK(CWorld::Players[CWorld::PlayerInFocus].SavePlayerInfo);
+	WRITE_BLOCK(CStats::SaveStats);
+	WRITE_BLOCK(CStreaming::MemoryCardSave);
+	WRITE_BLOCK(CPedType::Save);
+
+	// Write padding
+	i = 0;
+	do {
+		size = align4bytes(SIZE_OF_ONE_GAME_IN_BYTES - totalSize - 4);
+		if (size > sizeof(work_buff))
+			size = sizeof(work_buff);
+		if (size > 4) {
+			if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, size))
+				return false;
+			totalSize += size;
+		}
+		i++;
+	} while (i < 4);
+	
+	// Write checksum and close
+	CFileMgr::Write(file, (const char *) &CheckSum, sizeof(CheckSum));
+	if (CFileMgr::GetErrorReadWrite(file)) {
+		PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_WRITE;
+		if (CloseFile(file))
+			PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
+		return false;
+	}
+	
+	return true;
+}
+
 bool
 ReadInSizeofSaveFileBuffer(int32 &file, uint32 &size)
 {
@@ -246,7 +408,7 @@ align4bytes(int32 size)
 }
 
 STARTPATCHES
-	//InjectHook(0x58F8D0, GenericSave, PATCH_JUMP);
+	InjectHook(0x58F8D0, GenericSave, PATCH_JUMP);
 	//InjectHook(0x590A00, GenericLoad, PATCH_JUMP);
 	InjectHook(0x591910, ReadInSizeofSaveFileBuffer, PATCH_JUMP);
 	InjectHook(0x591990, ReadDataFromFile, PATCH_JUMP);