Skip to content

New vehicle features functions (setVehicleSpecialFeatureEnabled) #4330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 78 additions & 2 deletions Client/game_sa/CAutomobileSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void CAutomobileSAInterface::SetPanelDamage(std::uint8_t panelId, bool breakGlas
if (nodeId < 0)
return;

eCarNodes node = static_cast<eCarNodes>(nodeId);
CarNodes::Enum node = static_cast<CarNodes::Enum>(nodeId);

RwFrame* frame = m_aCarNodes[nodeId];
if (!frame)
Expand All @@ -47,7 +47,7 @@ void CAutomobileSAInterface::SetPanelDamage(std::uint8_t panelId, bool breakGlas
if ((pHandlingData->uiModelFlags & 0x10000000) != 0) // check bouncePanels flag
return;

if (node != eCarNodes::WINDSCREEN && node != eCarNodes::WING_LF && node != eCarNodes::WING_RF)
if (node != CarNodes::Enum::WINDSCREEN && node != CarNodes::Enum::WING_LF && node != CarNodes::Enum::WING_RF)
{
// Get free bouncing panel
for (auto& panel : m_panels)
Expand Down Expand Up @@ -87,3 +87,79 @@ void CAutomobileSAInterface::SetPanelDamage(std::uint8_t panelId, bool breakGlas
}
}
}

void CAutomobileSA::PreRender_End(CAutomobileSAInterface* vehicleInterface)
{
auto* vehicle = pGame->GetPools()->GetVehicle(reinterpret_cast<DWORD*>(vehicleInterface));
if (!vehicle || !vehicle->pEntity)
return;

// Support for default vehicles is still in the GTA code, so we don't need to do it again
if (vehicleInterface->m_nModelIndex == 407 || vehicleInterface->m_nModelIndex == 601)
return;

// Simple turret like in fire truck
if (vehicle->pEntity->IsSpecialFeatureEnabled(VehicleFeatures::Enum::WATER_CANNON) && !vehicle->pEntity->IsSpecialFeatureEnabled(VehicleFeatures::Enum::TURRET))
{
CVehicleSA::SetComponentRotation(vehicleInterface->m_aCarNodes[CarNodes::MISC_A], eComponentRotationAxis::AXIS_X, vehicleInterface->m_fDoomHorizontalRotation, true);
CVehicleSA::SetComponentRotation(vehicleInterface->m_aCarNodes[CarNodes::MISC_A], eComponentRotationAxis::AXIS_Z, vehicleInterface->m_fDoomVerticalRotation, false);
}

// Turret like rhino or swat van
if (vehicle->pEntity->IsSpecialFeatureEnabled(VehicleFeatures::Enum::TURRET))
{
CVehicleSA::SetComponentRotation(vehicleInterface->m_aCarNodes[CarNodes::MISC_A], eComponentRotationAxis::AXIS_Z, vehicleInterface->m_fDoomVerticalRotation, true);
CVehicleSA::SetComponentRotation(vehicleInterface->m_aCarNodes[CarNodes::MISC_B], eComponentRotationAxis::AXIS_X, vehicleInterface->m_fDoomHorizontalRotation, true);
}
}

bool CAutomobileSA::HasFeatureEnabled(CAutomobileSAInterface* vehicleInterface, VehicleFeatures::Enum feature)
{
auto* vehicle = pGame->GetPools()->GetVehicle(reinterpret_cast<DWORD*>(vehicleInterface));
if (!vehicle || !vehicle->pEntity) // This really shouldn't happen
return true;

return vehicle->pEntity->IsSpecialFeatureEnabled(feature);
}

static constexpr std::uintptr_t SKIIP_FIRE_TRUCK = 0x6B1F77;
static constexpr std::uintptr_t CONTINUE_FIRE_TRUCK = 0x6B1F5B;
static constexpr VehicleFeatures::Enum WATER_CANNON_ID = VehicleFeatures::Enum::WATER_CANNON;
static void _declspec(naked) HOOK_CAutomobile_ProcessControl_FireTruckCheck()
{
_asm
{
push WATER_CANNON_ID
push esi
call CAutomobileSA::HasFeatureEnabled
add esp, 8

test al, al
jz skip

jmp CONTINUE_FIRE_TRUCK

skip:
jmp SKIIP_FIRE_TRUCK
}
}

static constexpr std::uintptr_t FINISH_PRE_RENDER = 0x6ACC92;
static void _declspec(naked) HOOK_CAutomobile_PreRender_End()
{
_asm
{
push esi
call CAutomobileSA::PreRender_End
add esp, 4

lea ecx, [esp+94h]
jmp FINISH_PRE_RENDER
}
}

void CAutomobileSA::StaticSetHooks()
{
HookInstall(0x6B1F4B, (DWORD)HOOK_CAutomobile_ProcessControl_FireTruckCheck, 8); // Model check in CAutomobile::ProcessControl
HookInstall(0x6ACC8B, (DWORD)HOOK_CAutomobile_PreRender_End, 7); // The end of the CAutomobile::PreRender function
}
183 changes: 95 additions & 88 deletions Client/game_sa/CAutomobileSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,97 +42,97 @@ class CAutomobileSAInterface : public CVehicleSAInterface
public:
void SetPanelDamage(std::uint8_t panelId, bool breakGlass, bool spawnFlyingComponent = true);

CObjectSAInterface* SpawnFlyingComponent(const eCarNodes& nodeId, const eCarComponentCollisionTypes& collType)
CObjectSAInterface* SpawnFlyingComponent(const CarNodes::Enum& nodeId, const eCarComponentCollisionTypes& collType)
{
return ((CObjectSAInterface*(__thiscall*)(CAutomobileSAInterface*, eCarNodes, eCarComponentCollisionTypes))0x6a8580)(this, nodeId, collType);
return ((CObjectSAInterface*(__thiscall*)(CAutomobileSAInterface*, CarNodes::Enum, eCarComponentCollisionTypes))0x6a8580)(this, nodeId, collType);
}

CDamageManagerSAInterface m_damageManager;
CDoorSAInterface m_doors[MAX_DOORS];
RwFrame* m_aCarNodes[static_cast<std::size_t>(eCarNodes::NUM_NODES)];
CBouncingPanelSAInterface m_panels[3];
CDoorSAInterface m_swingingChassis;
CColPointSAInterface m_wheelColPoint[MAX_WHEELS];
float m_wheelsDistancesToGround1[4];
float m_wheelsDistancesToGround2[4];
float m_wheelCollisionState[4];
float field_800;
float field_804;
float field_80C;
int m_wheelSkidmarkType[4];
bool m_wheelSkidmarkBloodState[4];
bool m_wheelSkidmarkSomeBool[4];
float m_wheelRotation[4];
float m_wheelPosition[4];
float m_wheelSpeed[4];
int field_858[4];
char taxiAvaliable;
char field_869;
short field_86A;
unsigned short m_wMiscComponentAngle;
unsigned short m_wVoodooSuspension;
int m_dwBusDoorTimerEnd;
int m_dwBusDoorTimerStart;
float field_878;
float wheelOffsetZ[4];
int field_88C[3];
float m_fFrontHeightAboveRoad;
float m_fRearHeightAboveRoad;
float m_fCarTraction;
float m_fNitroValue;
int field_8A4;
int m_fRotationBalance; // used in CHeli::TestSniperCollision
float m_fMoveDirection;
int field_8B4[6];
int field_8C8[6];
float m_fBurningTime;
CEntitySAInterface* m_pWheelCollisionEntity[4];
CVector m_vWheelCollisionPos[4];
char field_924;
char field_925;
char field_926;
char field_927;
char field_928;
char field_929;
char field_92A;
char field_92B;
char field_92C;
char field_92D;
char field_92E;
char field_92F;
char field_930;
char field_931;
char field_932;
char field_933;
char field_934;
char field_935;
char field_936;
char field_937;
char field_938;
char field_939;
char field_93A;
char field_93B;
char field_93C;
char field_93D;
char field_93E;
char field_93F;
int field_940;
int field_944;
float m_fDoomVerticalRotation;
float m_fDoomHorizontalRotation;
float m_fForcedOrientation;
float m_fUpDownLightAngle[2];
unsigned char m_nNumContactWheels;
unsigned char m_nWheelsOnGround;
char field_962;
char field_963;
float field_964;
int m_wheelFrictionState[4];
CFxSystemSAInterface* pNitroParticle[2];
char field_980;
char field_981;
short field_982;
float field_984;
CDamageManagerSAInterface m_damageManager;
CDoorSAInterface m_doors[MAX_DOORS];
std::array<RwFrame*, CarNodes::Enum::NUM_NODES> m_aCarNodes;
CBouncingPanelSAInterface m_panels[3];
CDoorSAInterface m_swingingChassis;
CColPointSAInterface m_wheelColPoint[MAX_WHEELS];
float m_wheelsDistancesToGround1[4];
float m_wheelsDistancesToGround2[4];
float m_wheelCollisionState[4];
float field_800;
float field_804;
float field_80C;
int m_wheelSkidmarkType[4];
bool m_wheelSkidmarkBloodState[4];
bool m_wheelSkidmarkSomeBool[4];
float m_wheelRotation[4];
float m_wheelPosition[4];
float m_wheelSpeed[4];
int field_858[4];
char taxiAvaliable;
char field_869;
short field_86A;
unsigned short m_wMiscComponentAngle;
unsigned short m_wVoodooSuspension;
int m_dwBusDoorTimerEnd;
int m_dwBusDoorTimerStart;
float field_878;
float wheelOffsetZ[4];
int field_88C[3];
float m_fFrontHeightAboveRoad;
float m_fRearHeightAboveRoad;
float m_fCarTraction;
float m_fNitroValue;
int field_8A4;
int m_fRotationBalance; // used in CHeli::TestSniperCollision
float m_fMoveDirection;
int field_8B4[6];
int field_8C8[6];
float m_fBurningTime;
CEntitySAInterface* m_pWheelCollisionEntity[4];
CVector m_vWheelCollisionPos[4];
char field_924;
char field_925;
char field_926;
char field_927;
char field_928;
char field_929;
char field_92A;
char field_92B;
char field_92C;
char field_92D;
char field_92E;
char field_92F;
char field_930;
char field_931;
char field_932;
char field_933;
char field_934;
char field_935;
char field_936;
char field_937;
char field_938;
char field_939;
char field_93A;
char field_93B;
char field_93C;
char field_93D;
char field_93E;
char field_93F;
int field_940;
int field_944;
float m_fDoomVerticalRotation;
float m_fDoomHorizontalRotation;
float m_fForcedOrientation;
float m_fUpDownLightAngle[2];
unsigned char m_nNumContactWheels;
unsigned char m_nWheelsOnGround;
char field_962;
char field_963;
float field_964;
int m_wheelFrictionState[4];
CFxSystemSAInterface* pNitroParticle[2];
char field_980;
char field_981;
short field_982;
float field_984;
};
static_assert(sizeof(CAutomobileSAInterface) == 0x988, "Invalid size for CAutomobileSAInterface");

Expand All @@ -143,4 +143,11 @@ class CAutomobileSA : public virtual CAutomobile, public virtual CVehicleSA
CAutomobileSA(CAutomobileSAInterface* pInterface);

CAutomobileSAInterface* GetAutomobileInterface() { return reinterpret_cast<CAutomobileSAInterface*>(GetInterface()); }

static void StaticSetHooks();

private:
static void PreRender_End(CAutomobileSAInterface* vehicleInterface);

static bool HasFeatureEnabled(CAutomobileSAInterface* vehicleInterface, VehicleFeatures::Enum feature);
};
1 change: 1 addition & 0 deletions Client/game_sa/CGameSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ CGameSA::CGameSA()
CFireSA::StaticSetHooks();
CPtrNodeSingleLinkPoolSA::StaticSetHooks();
CVehicleAudioSettingsManagerSA::StaticSetHooks();
CAutomobileSA::StaticSetHooks();
}
catch (const std::bad_alloc& e)
{
Expand Down
8 changes: 8 additions & 0 deletions Client/game_sa/CGameSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "CPlantManagerSA.h"
#include "CRendererSA.h"
#include "CVehicleAudioSettingsManagerSA.h"
#include "CVehicleSA.h"

class CAnimBlendClumpDataSAInterface;
class CObjectGroupPhysicalPropertiesSA;
Expand Down Expand Up @@ -322,6 +323,13 @@ class CGameSA : public CGame

bool SetBuildingPoolSize(size_t size);

bool SetVehicleModelSpecialFeatureEnabled(std::uint16_t model, const VehicleFeatures::Enum& feature, bool enabled) override { return CVehicleSA::SetModelSpecialFeatureEnabled(model, feature, enabled); };
bool IsVehicleModelSpecialFeatureEnabled(std::uint16_t model, const VehicleFeatures::Enum& feature) const override { return CVehicleSA::IsModelSpecialFeatureEnabled(model, feature); };

ModelFeaturesArray GetModelSpecialFeatures(std::uint16_t model) const noexcept override { return CVehicleSA::GetModelSpecialFeatures(model); }

void ResetVehicleModelsSpecialFeatures() const noexcept override { CVehicleSA::ResetVehicleModelsSpecialFeatures(); };

private:
std::unique_ptr<CPools> m_Pools;
CPlayerInfo* m_pPlayerInfo;
Expand Down
Loading
Loading