Skip to content

Commit 1c9ba3d

Browse files
authored
Add vehicle dependent dummy positions (PR #1982)
1 parent 16a327b commit 1c9ba3d

20 files changed

+1467
-42
lines changed

Client/game_sa/CAutomobileSA.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class CAutomobileSAInterface : public CVehicleSAInterface
184184
char field_963;
185185
float field_964;
186186
int m_wheelFrictionState[4];
187-
void* pNitroParticle[2];
187+
CFxSystemSAInterface* pNitroParticle[2];
188188
char field_980;
189189
char field_981;
190190
short field_982;

Client/game_sa/CFxSystemSA.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,18 @@ void CFxSystemSA::GetPosition(CVector& vecPos)
6969

7070
void CFxSystemSA::SetPosition(const CVector& vecPos)
7171
{
72-
m_pInterface->matPosition.pos.x = vecPos.fX;
73-
m_pInterface->matPosition.pos.y = vecPos.fY;
74-
m_pInterface->matPosition.pos.z = vecPos.fZ;
72+
SetPosition(m_pInterface, vecPos);
73+
}
74+
75+
void CFxSystemSA::SetPosition(CFxSystemSAInterface* fxSystem, const CVector& position)
76+
{
77+
fxSystem->matPosition.pos.x = position.fX;
78+
fxSystem->matPosition.pos.y = position.fY;
79+
fxSystem->matPosition.pos.z = position.fZ;
7580

7681
// Set the update flag(s)
7782
// this is what RwMatrixUpdate (@0x7F18E0) does
78-
m_pInterface->matPosition.flags &= 0xFFFDFFFC;
83+
fxSystem->matPosition.flags &= 0xFFFDFFFC;
7984
}
8085

8186
float CFxSystemSA::GetEffectDensity()

Client/game_sa/CFxSystemSA.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ class CFxSystemSA : public CFxSystem
109109

110110
static void StaticSetHooks();
111111

112+
static void SetPosition(CFxSystemSAInterface* fxSystem, const CVector& position);
113+
112114
protected:
113115
CFxSystemSAInterface* m_pInterface;
114116
float m_fDrawDistance;

Client/game_sa/CModelInfoSA.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ std::map<CTimeInfoSAInterface*, CTimeInfoSAInterface*> CModelInfo
2525
std::unordered_map<DWORD, unsigned short> CModelInfoSA::ms_OriginalObjectPropertiesGroups;
2626
std::unordered_map<DWORD, std::pair<float, float>> CModelInfoSA::ms_VehicleModelDefaultWheelSizes;
2727

28+
static constexpr uintptr_t vftable_CVehicleModelInfo = 0x85C5C8u;
29+
2830
CModelInfoSA::CModelInfoSA()
2931
{
3032
m_pInterface = NULL;
@@ -247,9 +249,15 @@ BYTE CModelInfoSA::GetVehicleType()
247249
return bReturn;
248250
}
249251

250-
BOOL CModelInfoSA::IsVehicle()
252+
bool CModelInfoSA::IsVehicle() const
251253
{
252-
return GetVehicleType() != 0xFF;
254+
// NOTE(botder): This is from CModelInfo::IsVehicleModelType
255+
if (m_dwModelID >= 20000)
256+
return false;
257+
258+
// NOTE(botder): m_pInterface might be a nullptr here, we can't use it
259+
CBaseModelInfoSAInterface* model = ppModelInfo[m_dwModelID];
260+
return model != nullptr && reinterpret_cast<intptr_t>(model->VFTBL) == vftable_CVehicleModelInfo;
253261
}
254262

255263
bool CModelInfoSA::IsPlayerModel()
@@ -1016,6 +1024,40 @@ void CModelInfoSA::SetVehicleExhaustFumesPosition(const CVector& vecPosition)
10161024
return SetVehicleDummyPosition(eVehicleDummies::EXHAUST, vecPosition);
10171025
}
10181026

1027+
bool CModelInfoSA::GetVehicleDummyPositions(std::array<CVector, VEHICLE_DUMMY_COUNT>& positions) const
1028+
{
1029+
if (!IsVehicle())
1030+
return false;
1031+
1032+
CVector* dummyPositions = reinterpret_cast<CVehicleModelInfoSAInterface*>(m_pInterface)->pVisualInfo->vecDummies;
1033+
std::copy(dummyPositions, dummyPositions + positions.size(), positions.begin());
1034+
return true;
1035+
}
1036+
1037+
CVector CModelInfoSA::GetVehicleDummyDefaultPosition(eVehicleDummies eDummy)
1038+
{
1039+
if (!IsVehicle())
1040+
return CVector();
1041+
1042+
auto dummyIter = ms_ModelDefaultDummiesPosition.find(m_dwModelID);
1043+
1044+
if (dummyIter != ms_ModelDefaultDummiesPosition.end())
1045+
{
1046+
auto positionIter = dummyIter->second.find(eDummy);
1047+
1048+
if (positionIter != dummyIter->second.end())
1049+
{
1050+
return positionIter->second;
1051+
}
1052+
}
1053+
1054+
if (!IsLoaded())
1055+
Request(BLOCKING, "GetVehicleDummyDefaultPosition");
1056+
1057+
auto modelInfo = reinterpret_cast<CVehicleModelInfoSAInterface*>(m_pInterface);
1058+
return modelInfo->pVisualInfo->vecDummies[eDummy];
1059+
}
1060+
10191061
CVector CModelInfoSA::GetVehicleDummyPosition(eVehicleDummies eDummy)
10201062
{
10211063
if (!IsVehicle())

Client/game_sa/CModelInfoSA.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ class CModelInfoSA : public CModelInfo
335335
BOOL IsQuadBike();
336336
BOOL IsBmx();
337337
BOOL IsTrailer();
338-
BOOL IsVehicle();
338+
bool IsVehicle() const override;
339339
BOOL IsUpgrade();
340340

341341
char* GetNameIfVehicle();
@@ -383,7 +383,9 @@ class CModelInfoSA : public CModelInfo
383383
void* SetVehicleSuspensionData(void* pSuspensionLines);
384384
CVector GetVehicleExhaustFumesPosition() override;
385385
void SetVehicleExhaustFumesPosition(const CVector& vecPosition) override;
386+
CVector GetVehicleDummyDefaultPosition(eVehicleDummies eDummy) override;
386387
CVector GetVehicleDummyPosition(eVehicleDummies eDummy) override;
388+
bool GetVehicleDummyPositions(std::array<CVector, VEHICLE_DUMMY_COUNT>& positions) const override;
387389
void SetVehicleDummyPosition(eVehicleDummies eDummy, const CVector& vecPosition) override;
388390
void ResetVehicleDummies(bool bRemoveFromDummiesMap);
389391
static void ResetAllVehicleDummies();

Client/game_sa/CPoolsSA.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,15 @@ CVehicle* CPoolsSA::AddVehicle(CClientVehicle* pClientVehicle, eVehicleTypes eVe
9797

9898
if (m_vehiclePool.ulCount < MAX_VEHICLES)
9999
{
100-
eVehicleModelTypes eVehicleModelType = (eVehicleModelTypes)pGame->GetModelInfo(eVehicleType)->GetVehicleType();
100+
auto vehicleClass = static_cast<VehicleClass>(pGame->GetModelInfo(eVehicleType)->GetVehicleType());
101101

102-
switch (eVehicleModelType)
102+
switch (vehicleClass)
103103
{
104-
case eVehicleModelTypes::BOAT:
104+
case VehicleClass::BOAT:
105105
pVehicle = new CBoatSA(eVehicleType, ucVariation, ucVariation2);
106106
break;
107-
case eVehicleModelTypes::BMX:
108-
case eVehicleModelTypes::BIKE:
107+
case VehicleClass::BMX:
108+
case VehicleClass::BIKE:
109109
pVehicle = new CBikeSA(eVehicleType, ucVariation, ucVariation2);
110110
break;
111111
default:
@@ -147,20 +147,19 @@ CVehicle* CPoolsSA::AddVehicle(CClientVehicle* pClientVehicle, DWORD* pGameInter
147147
}
148148
else
149149
{
150-
151-
switch ((eVehicleModelTypes)pInterface->m_type)
152-
{
153-
case eVehicleModelTypes::BOAT:
154-
pVehicle = new CBoatSA(reinterpret_cast<CBoatSAInterface*>(pInterface));
150+
switch ((VehicleClass)pInterface->m_vehicleClass)
151+
{
152+
case VehicleClass::BOAT:
153+
pVehicle = new CBoatSA(reinterpret_cast<CBoatSAInterface*>(pInterface));
155154
break;
156-
case eVehicleModelTypes::BMX:
157-
case eVehicleModelTypes::BIKE:
155+
case VehicleClass::BMX:
156+
case VehicleClass::BIKE:
158157
pVehicle = new CBikeSA(reinterpret_cast<CBikeSAInterface*>(pInterface));
159158
break;
160159
default:
161160
pVehicle = new CVehicleSA(pInterface);
162161
break;
163-
}
162+
}
164163

165164
if (!AddVehicleToPool(pClientVehicle, pVehicle))
166165
{

Client/game_sa/CVehicleSA.cpp

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,16 @@ void CVehicleSA::Init()
204204
GetVehicleInterface()->m_pVehicle = this;
205205
g_bVehiclePointerInvalid = false;
206206

207+
CModelInfo* modelInfo = pGame->GetModelInfo(GetModelIndex());
208+
209+
if (modelInfo != nullptr)
210+
{
211+
for (size_t i = 0; i < m_dummyPositions.size(); ++i)
212+
{
213+
m_dummyPositions[i] = modelInfo->GetVehicleDummyPosition((eVehicleDummies)i);
214+
}
215+
}
216+
207217
// Unlock doors as they spawn randomly with locked doors
208218
LockDoors(false);
209219

@@ -1950,14 +1960,13 @@ void CVehicleSA::SetBikeWheelStatus(BYTE bWheel, BYTE bStatus)
19501960
bool CVehicleSA::IsWheelCollided(BYTE eWheelPosition)
19511961
{
19521962
auto vehicle = static_cast<CAutomobileSAInterface*>(GetInterface());
1953-
switch (vehicle->m_type)
1963+
switch ((VehicleClass)vehicle->m_vehicleClass)
19541964
{
1955-
case 0:
1965+
case VehicleClass::AUTOMOBILE:
19561966
if (eWheelPosition < 4)
19571967
return vehicle->m_wheelCollisionState[eWheelPosition] == 4.f;
19581968
break;
1959-
1960-
case 9:
1969+
case VehicleClass::BIKE:
19611970
if (eWheelPosition < 2)
19621971
return *(float*)((DWORD)vehicle + 0x730 + eWheelPosition * 8) == 4.f || *(float*)((DWORD)vehicle + 0x734 + eWheelPosition * 8) == 4.f;
19631972
break;
@@ -2668,6 +2677,63 @@ void CVehicleSA::UpdateLandingGearPosition()
26682677
}
26692678
}
26702679
}
2680+
2681+
bool CVehicleSA::GetDummyPosition(eVehicleDummies dummy, CVector& position) const
2682+
{
2683+
if (dummy >= 0 && dummy < VEHICLE_DUMMY_COUNT)
2684+
{
2685+
position = m_dummyPositions[dummy];
2686+
return true;
2687+
}
2688+
2689+
return false;
2690+
}
2691+
2692+
bool CVehicleSA::SetDummyPosition(eVehicleDummies dummy, const CVector& position)
2693+
{
2694+
if (dummy < 0 || dummy >= VEHICLE_DUMMY_COUNT)
2695+
return false;
2696+
2697+
auto vehicle = reinterpret_cast<CVehicleSAInterface*>(m_pInterface);
2698+
2699+
m_dummyPositions[dummy] = position;
2700+
2701+
if (dummy == ENGINE)
2702+
{
2703+
if (vehicle->m_overheatParticle != nullptr)
2704+
CFxSystemSA::SetPosition(vehicle->m_overheatParticle, position);
2705+
2706+
if (vehicle->m_fireParticle != nullptr)
2707+
CFxSystemSA::SetPosition(vehicle->m_fireParticle, position);
2708+
}
2709+
2710+
bool isAutomobileClass = static_cast<VehicleClass>(vehicle->m_vehicleClass) == VehicleClass::AUTOMOBILE;
2711+
2712+
if (isAutomobileClass)
2713+
{
2714+
SetAutomobileDummyPosition(reinterpret_cast<CAutomobileSAInterface*>(m_pInterface), dummy, position);
2715+
}
2716+
2717+
return true;
2718+
}
2719+
2720+
//
2721+
// NOTE(botder): Move the code to CAutomobileSA::SetDummyPosition, when we start using CAutomobileSA
2722+
//
2723+
void CVehicleSA::SetAutomobileDummyPosition(CAutomobileSAInterface* automobile, eVehicleDummies dummy, const CVector& position)
2724+
{
2725+
if (dummy == EXHAUST)
2726+
{
2727+
if (automobile->pNitroParticle[0] != nullptr)
2728+
CFxSystemSA::SetPosition(automobile->pNitroParticle[0], position);
2729+
}
2730+
else if (dummy == EXHAUST_SECONDARY)
2731+
{
2732+
if (automobile->pNitroParticle[1] != nullptr)
2733+
CFxSystemSA::SetPosition(automobile->pNitroParticle[1], position);
2734+
}
2735+
}
2736+
26712737
// Change plate text of existing vehicle
26722738
bool CVehicleSA::SetPlateText(const SString& strText)
26732739
{

Client/game_sa/CVehicleSA.h

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,6 @@ class CAutoPilot
326326

327327
#define MAX_UPGRADES_ATTACHED 15 // perhaps?
328328

329-
/**
330-
* \todo GAME RELEASE: Update CVehicleSAInterface
331-
*/
332329
class CVehicleSAInterface : public CPhysicalSAInterface
333330
{
334331
public:
@@ -424,22 +421,31 @@ class CVehicleSAInterface : public CPhysicalSAInterface
424421
unsigned int m_isUsingHornOrSecondarySiren;
425422

426423
// 1304
427-
BYTE Padding220[112];
424+
uint8_t Padding220[96];
425+
426+
// 1400
427+
CFxSystemSAInterface* m_overheatParticle;
428+
CFxSystemSAInterface* m_fireParticle;
429+
CFxSystemSAInterface* m_dustParticle;
430+
uint32_t m_renderLights;
428431

429432
// 1416
430433
RwTexture* m_pCustomPlateTexture;
431434

432-
// 1420
433-
BYTE Padding225[4];
435+
float m_steeringLeftRight;
434436

435437
// 1424
436-
BYTE m_type; // 0 = car/plane, 5 = boat, 6 = train, 9 = bike
438+
uint8_t m_vehicleClass;
439+
uint32_t m_vehicleSubClass;
437440

438-
// 1425
439-
BYTE Padding226[15];
441+
int16_t m_peviousRemapTxd;
442+
int16_t m_remapTxd;
443+
RwTexture* m_pRemapTexture;
440444
};
441445
static_assert(sizeof(CVehicleSAInterface) == 1440, "Invalid size for CVehicleSAInterface");
442446

447+
class CAutomobileSAInterface;
448+
443449
class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA
444450
{
445451
friend class CPoolsSA;
@@ -466,6 +472,8 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA
466472
unsigned char m_ucVariantCount;
467473
bool m_doorsUndamageable = false;
468474

475+
std::array<CVector, VEHICLE_DUMMY_COUNT> m_dummyPositions;
476+
469477
public:
470478
CVehicleSA();
471479
CVehicleSA(CVehicleSAInterface* vehicleInterface);
@@ -745,7 +753,15 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA
745753

746754
CAEVehicleAudioEntitySA* GetVehicleAudioEntity() { return m_pVehicleAudioEntity; };
747755

756+
bool GetDummyPosition(eVehicleDummies dummy, CVector& position) const override;
757+
bool SetDummyPosition(eVehicleDummies dummy, const CVector& position) override;
758+
759+
CVector* GetDummyPositions() { return m_dummyPositions.data(); }
760+
const CVector* GetDummyPositions() const override { return m_dummyPositions.data(); }
761+
748762
private:
763+
static void SetAutomobileDummyPosition(CAutomobileSAInterface* automobile, eVehicleDummies dummy, const CVector& position);
764+
749765
void RecalculateSuspensionLines();
750766
void CopyGlobalSuspensionLinesToPrivate();
751767
SVehicleFrame* GetVehicleComponent(const SString& vehicleComponent);

0 commit comments

Comments
 (0)