From 12f009e708b5969cd42ccf5bfb60be37b70f31d8 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Wed, 19 Jun 2019 23:41:43 +0200
Subject: implemented cHandlingDataMgr

---
 src/config.h                    |   1 -
 src/control/HandlingDataMgr.cpp | 242 +++++++++++++++++++++++++++++++++++++++-
 src/control/HandlingDataMgr.h   | 130 +++++++++++++++++++++
 src/control/ObjectData.cpp      |   2 +-
 src/control/Transmission.cpp    |  37 ++++++
 src/control/Transmission.h      |  26 +++++
 src/entities/Building.cpp       |  21 +++-
 src/entities/Building.h         |   3 +-
 8 files changed, 457 insertions(+), 5 deletions(-)
 create mode 100644 src/control/Transmission.cpp
 create mode 100644 src/control/Transmission.h

(limited to 'src')

diff --git a/src/config.h b/src/config.h
index 71689778..933aa53f 100644
--- a/src/config.h
+++ b/src/config.h
@@ -42,7 +42,6 @@ enum Config {
 	NUMATTRIBZONES = 288,
 	NUMZONEINDICES = 55000,
 
-	NUMPEDSTATS = 35,
 	NUMHANDLINGS = 57,
 
 	PATHNODESIZE = 4500,
diff --git a/src/control/HandlingDataMgr.cpp b/src/control/HandlingDataMgr.cpp
index 94824358..48000b48 100644
--- a/src/control/HandlingDataMgr.cpp
+++ b/src/control/HandlingDataMgr.cpp
@@ -1,7 +1,247 @@
 #include "common.h"
 #include "patcher.h"
+#include "main.h"
+#include "FileMgr.h"
 #include "HandlingDatamgr.h"
 
 cHandlingDataMgr &mod_HandlingManager = *(cHandlingDataMgr*)0x728060;
 
-WRAPPER int32 cHandlingDataMgr::GetHandlingId(const char *name){ EAXJMP(0x546B70); }
+char *HandlingFilename = "HANDLING.CFG";
+
+char VehicleNames[NUMHANDLINGS][14] = {
+	"LANDSTAL",
+	"IDAHO",
+	"STINGER",
+	"LINERUN",
+	"PEREN",
+	"SENTINEL",
+	"PATRIOT",
+	"FIRETRUK",
+	"TRASH",
+	"STRETCH",
+	"MANANA",
+	"INFERNUS",
+	"BLISTA",
+	"PONY",
+	"MULE",
+	"CHEETAH",
+	"AMBULAN",
+	"FBICAR",
+	"MOONBEAM",
+	"ESPERANT",
+	"TAXI",
+	"KURUMA",
+	"BOBCAT",
+	"MRWHOOP",
+	"BFINJECT",
+	"POLICE",
+	"ENFORCER",
+	"SECURICA",
+	"BANSHEE",
+	"PREDATOR",
+	"BUS",
+	"RHINO",
+	"BARRACKS",
+	"TRAIN",
+	"HELI",
+	"DODO",
+	"COACH",
+	"CABBIE",
+	"STALLION",
+	"RUMPO",
+	"RCBANDIT",
+	"BELLYUP",
+	"MRWONGS",
+	"MAFIA",
+	"YARDIE",
+	"YAKUZA",
+	"DIABLOS",
+	"COLUMB",
+	"HOODS",
+	"AIRTRAIN",
+	"DEADDODO",
+	"SPEEDER",
+	"REEFER",
+	"PANLANT",
+	"FLATBED",
+	"YANKEE",
+	"BORGNINE"
+};
+
+cHandlingDataMgr::cHandlingDataMgr(void)
+{
+	memset(this, 0, sizeof(this));
+}
+
+void
+cHandlingDataMgr::Initialise(void)
+{
+	LoadHandlingData();
+	field_0 = 0.1f;
+	field_4 = 0.9f;
+	field_8 = 1.0f;
+	field_C = 0.8f;
+	field_10 = 0.98f;
+}
+
+void
+cHandlingDataMgr::LoadHandlingData(void)
+{
+	char *start, *end;
+	char line[201];	// weird value
+	char delim[4];	// not sure
+	char *word;
+	int field, handlingId;
+	int keepGoing;
+	tHandlingData *handling;
+
+	CFileMgr::SetDir("DATA");
+	CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r");
+	CFileMgr::SetDir("");
+
+	start = (char*)work_buff;
+	end = start+1;
+	handling = nil;
+	keepGoing = 1;
+
+	while(keepGoing){
+		// find end of line
+		while(*end != '\n') end++;
+
+		// get line
+		strncpy(line, start, end - start);
+		line[end - start] = '\0';
+		start = end+1;
+		end = start+1;
+
+		// yeah, this is kinda crappy
+		if(strncmp(line, ";the end", 9) == 0)
+			keepGoing = 0;
+		else if(line[0] != ';'){
+			field = 0;
+			strcpy(delim, " \t");
+			// FIX: game seems to use a do-while loop here
+			for(word = strtok(line, delim); word; word = strtok(nil, delim)){
+				switch(field){
+				case  0:
+					handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS);
+					assert(handlingId >= 0 && handlingId < NUMHANDLINGS);
+					handling = &HandlingData[handlingId];
+					handling->nIdentifier = handlingId;
+					break;
+				case  1: handling->fMass = strtod(word, nil); break;
+				case  2: handling->Dimension.x = strtod(word, nil); break;
+				case  3: handling->Dimension.y = strtod(word, nil); break;
+				case  4: handling->Dimension.z = strtod(word, nil); break;
+				case  5: handling->CentreOfMass.x = strtod(word, nil); break;
+				case  6: handling->CentreOfMass.y = strtod(word, nil); break;
+				case  7: handling->CentreOfMass.z = strtod(word, nil); break;
+				case  8: handling->nPercentSubmerged = atoi(word); break;
+				case  9: handling->fTractionMultiplier = strtod(word, nil); break;
+				case 10: handling->fTractionLoss = strtod(word, nil); break;
+				case 11: handling->fTractionBias = strtod(word, nil); break;
+				case 12: handling->TransmissionData.nNumberOfGears = atoi(word); break;
+				case 13: handling->TransmissionData.fMaxVelocity = strtod(word, nil); break;
+				case 14: handling->TransmissionData.fEngineAcceleration = strtod(word, nil) * 0.4f; break;
+				case 15: handling->TransmissionData.nDriveType = word[0]; break;
+				case 16: handling->TransmissionData.nEngineType = word[0]; break;
+				case 17: handling->fBrakeDeceleration = strtod(word, nil); break;
+				case 18: handling->fBrakeBias = strtod(word, nil); break;
+				case 19: handling->bABS = !!atoi(word); break;
+				case 20: handling->fSteeringLock = strtod(word, nil); break;
+				case 21: handling->fSuspensionForceLevel = strtod(word, nil); break;
+				case 22: handling->fSuspensionDampingLevel = strtod(word, nil); break;
+				case 23: handling->fSeatOffsetDistance = strtod(word, nil); break;
+				case 24: handling->fCollisionDamageMultiplier = strtod(word, nil); break;
+				case 25: handling->nMonetaryValue = atoi(word); break;
+				case 26: handling->fSuspensionUpperLimit = strtod(word, nil); break;
+				case 27: handling->fSuspensionLowerLimit = strtod(word, nil); break;
+				case 28: handling->fSuspensionBias = strtod(word, nil); break;
+				case 29:
+					sscanf(word, "%x", &handling->Flags);
+					handling->TransmissionData.Flags = handling->Flags;
+					break;
+				case 30: handling->FrontLights = atoi(word); break;
+				case 31: handling->RearLights = atoi(word); break;
+				}
+				field++;
+			}
+			ConvertDataToGameUnits(handling);
+		}
+	}
+}
+
+int
+cHandlingDataMgr::FindExactWord(const char *word, const char *words, int wordLen, int numWords)
+{
+	int i;
+
+	for(i = 0; i < numWords; i++){
+		// BUG: the game does something really stupid here, it's fixed here
+		if(strncmp(word, words, wordLen) == 0)
+			return i;
+		words += wordLen;
+	}
+	return numWords;
+}
+
+
+void
+cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
+{
+	// TODO: figure out what exactly is being converted here
+	float velocity, a, b, specificVolume;
+
+	handling->TransmissionData.fEngineAcceleration /= 2500.0f;
+	handling->TransmissionData.fMaxVelocity /= 180.0f;
+	handling->fBrakeDeceleration /= 2500.0f;
+	handling->fTurnMass = (sq(handling->Dimension.x) + sq(handling->Dimension.y)) * handling->fMass / 12.0f;
+	if(handling->fTurnMass < 10.0f)
+		handling->fTurnMass *= 5.0f;
+	handling->fInvMass = 1.0f/handling->fMass;
+	handling->fBuoyancy = 100.0f/handling->nPercentSubmerged * 0.008*handling->fMass;
+
+	// What the hell is going on here?
+	specificVolume = handling->Dimension.x*handling->Dimension.z*0.5f / handling->fMass;	// ?
+	a = 0.0f;
+	b = 100.0f;
+	velocity = handling->TransmissionData.fMaxVelocity;
+	while(a < b && velocity > 0.0f){
+		velocity -= 0.01;
+		a = handling->TransmissionData.fEngineAcceleration/6.0f;
+		b = -velocity * (1.0f/(specificVolume * sq(velocity) + 1.0f) - 1.0f);
+	}
+
+	if(handling->nIdentifier == HANDLING_RCBANDIT){
+		handling->TransmissionData.fUnkMaxVelocity = handling->TransmissionData.fMaxVelocity;
+	}else{
+		handling->TransmissionData.fUnkMaxVelocity = velocity;
+		handling->TransmissionData.fMaxVelocity = velocity * 1.2f;
+	}
+	handling->TransmissionData.fMaxReverseVelocity = -0.2f;
+
+	if(handling->TransmissionData.nDriveType == '4')
+		handling->TransmissionData.fEngineAcceleration /= 4.0f;
+	else
+		handling->TransmissionData.fEngineAcceleration /= 2.0f;
+
+	handling->TransmissionData.InitGearRatios();
+}
+
+int32
+cHandlingDataMgr::GetHandlingId(const char *name)
+{
+	int i;
+	for(i = 0; i < NUMHANDLINGS; i++)
+		if(strncmp(VehicleNames[i], name, 14) == 0)
+			break;
+	return i;
+}
+
+STARTPATCHES
+	InjectHook(0x546D80, &cHandlingDataMgr::Initialise, PATCH_JUMP);
+	InjectHook(0x546DB0, &cHandlingDataMgr::LoadHandlingData, PATCH_JUMP);
+	InjectHook(0x546BB0, &cHandlingDataMgr::ConvertDataToGameUnits, PATCH_JUMP);
+	InjectHook(0x546AA0, &cHandlingDataMgr::FindExactWord, PATCH_JUMP);
+	InjectHook(0x546B70, &cHandlingDataMgr::GetHandlingId, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/control/HandlingDataMgr.h b/src/control/HandlingDataMgr.h
index 00e62b59..216aa7e8 100644
--- a/src/control/HandlingDataMgr.h
+++ b/src/control/HandlingDataMgr.h
@@ -1,8 +1,138 @@
 #pragma once
 
+#include "Transmission.h"
+
+enum eHandlingId
+{
+	HANDLING_LANDSTAL,
+	HANDLING_IDAHO,
+	HANDLING_STINGER,
+	HANDLING_LINERUN,
+	HANDLING_PEREN,
+	HANDLING_SENTINEL,
+	HANDLING_PATRIOT,
+	HANDLING_FIRETRUK,
+	HANDLING_TRASH,
+	HANDLING_STRETCH,
+	HANDLING_MANANA,
+	HANDLING_INFERNUS,
+	HANDLING_BLISTA,
+	HANDLING_PONY,
+	HANDLING_MULE,
+	HANDLING_CHEETAH,
+	HANDLING_AMBULAN,
+	HANDLING_FBICAR,
+	HANDLING_MOONBEAM,
+	HANDLING_ESPERANT,
+	HANDLING_TAXI,
+	HANDLING_KURUMA,
+	HANDLING_BOBCAT,
+	HANDLING_MRWHOOP,
+	HANDLING_BFINJECT,
+	HANDLING_POLICE,
+	HANDLING_ENFORCER,
+	HANDLING_SECURICA,
+	HANDLING_BANSHEE,
+	HANDLING_PREDATOR,
+	HANDLING_BUS,
+	HANDLING_RHINO,
+	HANDLING_BARRACKS,
+	HANDLING_TRAIN,
+	HANDLING_HELI,
+	HANDLING_DODO,
+	HANDLING_COACH,
+	HANDLING_CABBIE,
+	HANDLING_STALLION,
+	HANDLING_RUMPO,
+	HANDLING_RCBANDIT,
+	HANDLING_BELLYUP,
+	HANDLING_MRWONGS,
+	HANDLING_MAFIA,
+	HANDLING_YARDIE,
+	HANDLING_YAKUZA,
+	HANDLING_DIABLOS,
+	HANDLING_COLUMB,
+	HANDLING_HOODS,
+	HANDLING_AIRTRAIN,
+	HANDLING_DEADDODO,
+	HANDLING_SPEEDER,
+	HANDLING_REEFER,
+	HANDLING_PANLANT,
+	HANDLING_FLATBED,
+	HANDLING_YANKEE,
+	HANDLING_BORGNINE
+};
+
+enum
+{
+	HANDLING_1G_BOOST = 1,
+	HANDLING_2G_BOOST = 2,
+	HANDLING_REV_BONNET = 4,
+	HANDLING_HANGING_BOOT = 8,
+	HANDLING_NO_DOORS = 0x10,
+	HANDLING_IS_VAN = 0x20,
+	HANDLING_IS_BUS = 0x40,
+	HANDLING_IS_LOW = 0x80,
+	HANDLING_DBL_EXHAUST = 0x100,
+	HANDLING_TAILGATE_BOOT = 0x200,
+	HANDLING_NOSWING_BOOT = 0x400,
+	HANDLING_NONPLAYER_STABILISER = 0x800,
+	HANDLING_NEUTRALHANDLING = 0x1000,
+	HANDLING_HAS_NO_ROOF = 0x2000,
+	HANDLING_IS_BIG = 0x4000,
+	HANDLING_HALOGEN_LIGHTS = 0x8000,
+};
+
+struct tHandlingData
+{
+	int32 nIdentifier;
+	float fMass;
+	float fInvMass;
+	float fTurnMass;
+	CVector Dimension;
+	CVector CentreOfMass;
+	int8 nPercentSubmerged;
+	float fBuoyancy;
+	float fTractionMultiplier;
+	cTransmission TransmissionData;
+	float fBrakeDeceleration;
+	float fBrakeBias;
+	int8 bABS;
+	float fSteeringLock;
+	float fTractionLoss;
+	float fTractionBias;
+ uint32 field_AC;
+	float fSuspensionForceLevel;
+	float fSuspensionDampingLevel;
+	float fSuspensionUpperLimit;
+	float fSuspensionLowerLimit;
+	float fSuspensionBias;
+	float fCollisionDamageMultiplier;
+	uint32 Flags;
+	float fSeatOffsetDistance;
+	int32 nMonetaryValue;
+	int8 FrontLights;
+	int8 RearLights;
+};
+VALIDATE_SIZE(tHandlingData, 0xD8);
+
 class cHandlingDataMgr
 {
+	float field_0;	// unused it seems
+	float field_4;	// wheel related
+	float field_8;	//
+	float field_C;	// unused it seems
+	float field_10;	//
+	tHandlingData HandlingData[NUMHANDLINGS];
+	uint32 field_302C;	// unused it seems, padding?
+
 public:
+	cHandlingDataMgr(void);
+	void Initialise(void);
+	void LoadHandlingData(void);
+	int FindExactWord(const char *word, const char *words, int wordLen, int numWords);
+	void ConvertDataToGameUnits(tHandlingData *handling);
 	int32 GetHandlingId(const char *name);
 };
+VALIDATE_SIZE(cHandlingDataMgr, 0x3030);
 extern cHandlingDataMgr &mod_HandlingManager;
diff --git a/src/control/ObjectData.cpp b/src/control/ObjectData.cpp
index a0838007..ef5bcc5e 100644
--- a/src/control/ObjectData.cpp
+++ b/src/control/ObjectData.cpp
@@ -20,7 +20,7 @@ CObjectData::Initialise(const char *filename)
 	CBaseModelInfo *mi;
 
 	CFileMgr::SetDir("");
-	CFileMgr::LoadFile(filename, work_buff, 55000, "r");
+	CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r");
 
 	id = 0;
 	p = (char*)work_buff;
diff --git a/src/control/Transmission.cpp b/src/control/Transmission.cpp
new file mode 100644
index 00000000..aaa24ced
--- /dev/null
+++ b/src/control/Transmission.cpp
@@ -0,0 +1,37 @@
+#include "common.h"
+#include "patcher.h"
+#include "Transmission.h"
+
+void
+cTransmission::InitGearRatios(void)
+{
+	static tGear *pGearRatio0 = nil;
+	static tGear *pGearRatio1 = nil;
+	int i;
+	float velocityDiff;
+
+	memset(Gears, 0, sizeof(Gears));
+
+	for(i = 1; i <= nNumberOfGears; i++){
+		pGearRatio0 = &Gears[i-1];
+		pGearRatio1 = &Gears[i];
+
+		pGearRatio1->fMaxVelocity = (float)i / nNumberOfGears * fMaxVelocity;
+
+		velocityDiff = pGearRatio1->fMaxVelocity - pGearRatio0->fMaxVelocity;
+
+		if(i >= nNumberOfGears){
+			pGearRatio1->fShiftUpVelocity = fMaxVelocity;
+		}else{
+			Gears[i+1].fShiftDownVelocity = velocityDiff*0.42f + pGearRatio0->fMaxVelocity;
+			pGearRatio1->fShiftUpVelocity = velocityDiff/0.6667f + pGearRatio0->fMaxVelocity;
+		}
+	}
+
+	// Reverse gear
+	Gears[0].fMaxVelocity = fMaxReverseVelocity;
+	Gears[0].fShiftUpVelocity = -0.01f;
+	Gears[0].fShiftDownVelocity = fMaxReverseVelocity;
+
+	Gears[1].fShiftDownVelocity = -0.01f;
+}
diff --git a/src/control/Transmission.h b/src/control/Transmission.h
new file mode 100644
index 00000000..686e0aca
--- /dev/null
+++ b/src/control/Transmission.h
@@ -0,0 +1,26 @@
+#pragma once
+
+struct tGear
+{
+	float fMaxVelocity;
+	float fShiftUpVelocity;
+	float fShiftDownVelocity;
+};
+
+class cTransmission
+{
+public:
+	// Gear 0 is reverse, 1-5 are forward
+	tGear Gears[6];
+	char nDriveType;
+	char nEngineType;
+	int8 nNumberOfGears;
+	uint8 Flags;
+	float fEngineAcceleration;
+	float fMaxVelocity;
+	float fUnkMaxVelocity;
+	float fMaxReverseVelocity;
+	float field_5C;
+
+	void InitGearRatios(void);
+};
diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp
index e8f19b01..ef236e89 100644
--- a/src/entities/Building.cpp
+++ b/src/entities/Building.cpp
@@ -1,7 +1,26 @@
 #include "common.h"
-#include "rpworld.h"
+#include "patcher.h"
 #include "Building.h"
+#include "Streaming.h"
 #include "Pools.h"
 
 void *CBuilding::operator new(size_t sz) { return CPools::GetBuildingPool()->New();  }
 void CBuilding::operator delete(void *p, size_t sz) { CPools::GetBuildingPool()->Delete((CBuilding*)p); }
+
+void
+CBuilding::ReplaceWithNewModel(int32 id)
+{
+	DeleteRwObject();
+
+	if(CModelInfo::GetModelInfo(m_modelIndex)->m_refCount == 0)
+		CStreaming::RemoveModel(m_modelIndex);
+	m_modelIndex = id;
+
+	if(bIsBIGBuilding)
+		if(m_level == LEVEL_NONE || m_level == CGame::currLevel)
+			CStreaming::RequestModel(id, STREAM_DONT_REMOVE);
+}
+
+STARTPATCHES
+	InjectHook(0x405850, &CBuilding::ReplaceWithNewModel, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/entities/Building.h b/src/entities/Building.h
index 612e0fb3..7b837f46 100644
--- a/src/entities/Building.h
+++ b/src/entities/Building.h
@@ -5,7 +5,6 @@
 class CBuilding : public CEntity
 {
 public:
-	// TODO: ReplaceWithNewModel
 	CBuilding(void) {
 		m_type = ENTITY_TYPE_BUILDING;
 		bUsesCollision = true;
@@ -13,6 +12,8 @@ public:
 	static void *operator new(size_t);
 	static void operator delete(void*, size_t);
 
+	void ReplaceWithNewModel(int32 id);
+
 	virtual bool GetIsATreadable(void) { return false; }
 };
 static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error");
-- 
cgit v1.2.3-70-g09d2