From fa29804c49faf9135b8c1929cc49e201024521c6 Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Sun, 3 May 2020 01:42:46 +0300
Subject: [PATCH 1/3] script compatibility

---
 src/control/Script.cpp | 80 ++++++++++++++++++++++++++++++++++++++++--
 src/control/Script.h   | 14 ++++----
 2 files changed, 83 insertions(+), 11 deletions(-)

diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index b63a5d87..433e0449 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -128,6 +128,14 @@ uint16 CTheScripts::CommandsExecuted;
 uint16 CTheScripts::ScriptsUpdated;
 int32 ScriptParams[32];
 
+
+const uint32 CRunningScript::nSaveStructSize =
+#ifdef COMPATIBLE_SAVES
+	136;	
+#else
+	sizeof(CRunningScript);
+#endif
+
 CMissionCleanup::CMissionCleanup()
 {
 	Init();
@@ -11188,7 +11196,7 @@ INITSAVEBUF
 	uint32 runningScripts = 0;
 	for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext())
 		runningScripts++;
-	*size = sizeof(CRunningScript) * runningScripts + varSpace + SCRIPT_DATA_SIZE + SAVE_HEADER_SIZE + 3 * sizeof(uint32);
+	*size = CRunningScript::nSaveStructSize * runningScripts + varSpace + SCRIPT_DATA_SIZE + SAVE_HEADER_SIZE + 3 * sizeof(uint32);
 	WriteSaveHeader(buf, 'S', 'C', 'R', '\0', *size - SAVE_HEADER_SIZE);
 	WriteSaveBuf(buf, varSpace);
 	for (uint32 i = 0; i < varSpace; i++)
@@ -11260,7 +11268,7 @@ INITSAVEBUF
 	WriteSaveBuf(buf, (uint16)0);
 	WriteSaveBuf(buf, runningScripts);
 	for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext())
-		WriteSaveBuf(buf, *pScript);
+		pScript->Save(buf);
 VALIDATESAVEBUF(*size)
 }
 
@@ -11336,7 +11344,7 @@ INITSAVEBUF
 	ReadSaveBuf<uint16>(buf);
 	uint32 runningScripts = ReadSaveBuf<uint32>(buf);
 	for (uint32 i = 0; i < runningScripts; i++)
-		StartNewScript(0)->BuildFromSaved(ReadSaveBuf<CRunningScript>(buf));
+		StartNewScript(0)->Load(buf);
 VALIDATESAVEBUF(size)
 }
 
@@ -11611,3 +11619,69 @@ void CTheScripts::ReadMultiScriptFileOffsetsFromScript()
 		MultiScriptArray[i] = Read4BytesFromScript(&ip);
 	}
 }
+
+void CRunningScript::Save(uint8*& buf)
+{
+#ifdef COMPATIBLE_SAVES
+	SkipSaveBuf(buf, 8);
+	for (int i = 0; i < 8; i++)
+		WriteSaveBuf<char>(buf, m_abScriptName[i]);
+	WriteSaveBuf<uint32>(buf, m_nIp);
+	static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6");
+	for (int i = 0; i < MAX_STACK_DEPTH; i++)
+		WriteSaveBuf<uint32>(buf, m_anStack[i]);
+	WriteSaveBuf<uint16>(buf, m_nStackPointer);
+	SkipSaveBuf(buf, 2);
+	static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18");
+	for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++)
+		WriteSaveBuf<int32>(buf, m_anLocalVariables[i]);
+	WriteSaveBuf<bool>(buf, m_bCondResult);
+	WriteSaveBuf<bool>(buf, m_bIsMissionScript);
+	WriteSaveBuf<bool>(buf, m_bSkipWakeTime);
+	SkipSaveBuf(buf, 1);
+	WriteSaveBuf<uint32>(buf, m_nWakeTime);
+	WriteSaveBuf<uint16>(buf, m_nAndOrState);
+	WriteSaveBuf<bool>(buf, m_bNotFlag);
+	WriteSaveBuf<bool>(buf, m_bDeatharrestEnabled);
+	WriteSaveBuf<bool>(buf, m_bDeatharrestExecuted);
+	WriteSaveBuf<bool>(buf, m_bMissionFlag);
+	SkipSaveBuf(buf, 2);
+#else
+	WriteSaveBuf(buf, *this);
+#endif
+}
+
+void CRunningScript::Load(uint8*& buf)
+{
+#ifdef COMPATIBLE_SAVES
+	SkipSaveBuf(buf, 8);
+	for (int i = 0; i < 8; i++)
+		m_abScriptName[i] = ReadSaveBuf<char>(buf);
+	m_nIp = ReadSaveBuf<uint32>(buf);
+	static_assert(MAX_STACK_DEPTH == 6, "Compatibility loss: MAX_STACK_DEPTH != 6");
+	for (int i = 0; i < MAX_STACK_DEPTH; i++)
+		m_anStack[i] = ReadSaveBuf<uint32>(buf);
+	m_nStackPointer = ReadSaveBuf<uint16>(buf);
+	SkipSaveBuf(buf, 2);
+	static_assert(NUM_LOCAL_VARS + NUM_TIMERS == 18, "Compatibility loss: NUM_LOCAL_VARS + NUM_TIMERS != 18");
+	for (int i = 0; i < NUM_LOCAL_VARS + NUM_TIMERS; i++)
+		m_anLocalVariables[i] = ReadSaveBuf<int32>(buf);
+	m_bCondResult = ReadSaveBuf<bool>(buf);
+	m_bIsMissionScript = ReadSaveBuf<bool>(buf);
+	m_bSkipWakeTime = ReadSaveBuf<bool>(buf);
+	SkipSaveBuf(buf, 1);
+	m_nWakeTime = ReadSaveBuf<uint32>(buf);
+	m_nAndOrState = ReadSaveBuf<uint16>(buf);
+	m_bNotFlag = ReadSaveBuf<bool>(buf);
+	m_bDeatharrestEnabled = ReadSaveBuf<bool>(buf);
+	m_bDeatharrestExecuted = ReadSaveBuf<bool>(buf);
+	m_bMissionFlag = ReadSaveBuf<bool>(buf);
+	SkipSaveBuf(buf, 2);
+#else
+	CRunningScript* n = next;
+	CRunningScript* p = prev;
+	*this = ReadSaveBuf<CRunningScript>(buf);
+	next = n;
+	prev = p;
+#endif
+}
diff --git a/src/control/Script.h b/src/control/Script.h
index 2eed29fe..01cad269 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -423,14 +423,10 @@ class CRunningScript
 public:
 	void SetIP(uint32 ip) { m_nIp = ip; }
 	CRunningScript* GetNext() const { return next; }
-	void BuildFromSaved(const CRunningScript& pSaved)
-	{
-		CRunningScript* n = next;
-		CRunningScript* p = prev;
-		*this = pSaved;
-		next = n;
-		prev = p;
-	}
+
+	void Save(uint8*& buf);
+	void Load(uint8*& buf);
+
 	void UpdateTimers(float timeStep) {
 		m_anLocalVariables[NUM_LOCAL_VARS] += timeStep;
 		m_anLocalVariables[NUM_LOCAL_VARS + 1] += timeStep;
@@ -442,6 +438,8 @@ public:
 	void RemoveScriptFromList(CRunningScript**);
 	void AddScriptToList(CRunningScript**);
 
+	static const uint32 nSaveStructSize;
+
 private:
 	void CollectParameters(uint32*, int16);
 	int32 CollectNextParameterWithoutIncreasingPC(uint32);

From d1a46c35ce4012e74b8a9955d8e6e4dcc562b57d Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Mon, 4 May 2020 14:57:49 +0300
Subject: [PATCH 2/3] fixed spawn bug

---
 src/control/CarCtrl.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 2d946145..09571b7f 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -422,8 +422,11 @@ CCarCtrl::GenerateOneRandomCar()
 #ifdef FIX_BUGS
 	/* Casting timer to float is very unwanted. In this case it's not awful */
 	/* but in CAutoPilot::ModifySpeed it can even cause crashes (see SilentPatch). */
+
+	/* Second fix: adding 0.5f is a mistake. It should be between 0 and 1. It was fixed in SA.*/
+	/* It is also correct in CAutoPilot::ModifySpeed. */
 	pCar->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
-		(uint32)((0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve);
+		(uint32)(positionBetweenNodes * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve);
 #else
 	pCar->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
 		(0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve;

From 11c7050dfb353d1b84503d9f798b8f1bfab296ae Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Mon, 4 May 2020 15:02:46 +0300
Subject: [PATCH 3/3] deny coach in crusher

---
 src/vehicles/Cranes.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/vehicles/Cranes.cpp b/src/vehicles/Cranes.cpp
index 1cace3e1..3ef11302 100644
--- a/src/vehicles/Cranes.cpp
+++ b/src/vehicles/Cranes.cpp
@@ -443,7 +443,9 @@ bool CCrane::DoesCranePickUpThisCarType(uint32 mi)
 	if (m_bIsCrusher) {
 		return mi != MI_FIRETRUCK &&
 			mi != MI_TRASH &&
-#ifndef FIX_BUGS // why
+#ifdef FIX_BUGS
+			mi != MI_COACH &&
+#else
 			mi != MI_BLISTA &&
 #endif
 			mi != MI_SECURICA &&