Skip to content

Add new function spawnVehicleFlyingComponent #3592

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

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 1 addition & 34 deletions Client/game_sa/CAutomobileSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,6 @@
#define MAX_PASSENGER_COUNT 8
#define MAX_DOORS 6 // also in CDamageManager

namespace eCarNode
{
enum
{
NONE = 0,
CHASSIS = 1,
WHEEL_RF = 2,
WHEEL_RM = 3,
WHEEL_RB = 4,
WHEEL_LF = 5,
WHEEL_LM = 6,
WHEEL_LB = 7,
DOOR_RF = 8,
DOOR_RR = 9,
DOOR_LF = 10,
DOOR_LR = 11,
BUMP_FRONT = 12,
BUMP_REAR = 13,
WING_RF = 14,
WING_LF = 15,
BONNET = 16,
BOOT = 17,
WINDSCREEN = 18,
EXHAUST = 19,
MISC_A = 20,
MISC_B = 21,
MISC_C = 22,
MISC_D = 23,
MISC_E = 24,
NUM_NODES
};
};

class CBouncingPanelSAInterface
{
public:
Expand All @@ -70,7 +37,7 @@ class CAutomobileSAInterface : public CVehicleSAInterface
public:
CDamageManagerSAInterface m_damageManager;
CDoorSAInterface m_doors[MAX_DOORS];
RwFrame* m_aCarNodes[eCarNode::NUM_NODES];
RwFrame* m_aCarNodes[static_cast<std::size_t>(eCarNodes::NUM_NODES)];
CBouncingPanelSAInterface m_panels[3];
CDoorSAInterface m_swingingChassis;
CColPointSAInterface m_wheelColPoint[MAX_WHEELS];
Expand Down
18 changes: 17 additions & 1 deletion Client/game_sa/CBikeSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@
#include <game/CBike.h>
#include "CVehicleSA.h"

enum class eBikeNodes
{
NONE = 0,
CHASSIS,
FORKS_FRONT,
FORKS_REAR,
WHEEL_FRONT,
WHEEL_REAR,
MUDGUARD,
HANDLEBARS,
MISC_A,
MISC_B,

NUM_NODES
};

struct sRideAnimData
{
int32 iAnimGroup;
Expand All @@ -29,7 +45,7 @@ static_assert(sizeof(sRideAnimData) == 0x1C, "Invalid size for sRideAnimData");
class CBikeSAInterface : public CVehicleSAInterface
{
public:
int32 m_apModelNodes[10];
RwFrame* m_apModelNodes[static_cast<std::size_t>(eBikeNodes::NUM_NODES)];
int8 m_bLeanMatrixCalculated;
int8 pad0[3]; // Maybe prev value is int32
int8 m_mLeanMatrix[72];
Expand Down
16 changes: 16 additions & 0 deletions Client/game_sa/CBmxSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@
#include <game/CBmx.h>
#include "CBikeSA.h"

enum class eBmxNodes
{
NONE = 0,
CHASSIS,
FORKS_FRONT,
FORKS_REAR,
WHEEL_FRONT,
WHEEL_REAR,
HANDLEBARS,
CHAINSET,
PEDAL_R,
PEDAL_L,

NUM_NODES
};

class CBmxSAInterface : public CBikeSAInterface
{
// fill this
Expand Down
20 changes: 19 additions & 1 deletion Client/game_sa/CBoatSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,30 @@
#include <game/CBoat.h>
#include "CVehicleSA.h"

enum class eBoatNodes
{
NONE = 0,
MOVING,
WINDSCREEN,
RUDDER,
FLAP_LEFT,
FLAP_RIGHT,
REARFLAP_LEFT,
REARFLAP_RIGHT,
STATIC_PROP,
MOVING_PROP,
STATIC_PROP2,
MOVING_PROP2,

NUM_NODES
};

class CBoatSAInterface : public CVehicleSAInterface
{
public:
uint32 pad1[3]; // 1440
uint32 BoatFlags; // 1452
RwFrame* pBoatParts[11]; // 1456 [[ find out correct size
RwFrame* pBoatParts[static_cast<std::size_t>(eBoatNodes::NUM_NODES)]; // 1456
uint32 pad2[3]; // 1500
uint16 pad3; // 1512
uint8 pad4[2]; // 1514
Expand Down
44 changes: 21 additions & 23 deletions Client/game_sa/CTrainSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,27 @@
#include "CVehicleSA.h"
#include "CDoorSA.h"

namespace eTrainNode
enum class eTrainNodes
{
enum
{
NONE = 0,
DOOR_LF = 1,
DOOR_RF = 2,
WHEEL_RF1 = 3,
WHEEL_RF2 = 4,
WHEEL_RF3 = 5,
WHEEL_RB1 = 6,
WHEEL_RB2 = 7,
WHEEL_RB3 = 8,
WHEEL_LF1 = 9,
WHEEL_LF2 = 10,
WHEEL_LF3 = 11,
WHEEL_LB1 = 12,
WHEEL_LB2 = 13,
WHEEL_LB3 = 14,
BOGIE_FRONT = 15,
BOGIE_REAR = 16,
NUM_NODES
};
NONE = 0,
DOOR_LF,
DOOR_RF,
WHEEL_RF1,
WHEEL_RF2,
WHEEL_RF3,
WHEEL_RB1,
WHEEL_RB2,
WHEEL_RB3,
WHEEL_LF1,
WHEEL_LF2,
WHEEL_LF3,
WHEEL_LB1,
WHEEL_LB2,
WHEEL_LB3,
BOGIE_FRONT,
BOGIE_REAR,

NUM_NODES
};

enum class eTrainPassengersGenerationState : unsigned char
Expand Down Expand Up @@ -101,7 +99,7 @@ class CTrainSAInterface : public CVehicleSAInterface
CTrainSAInterface* m_prevCarriage;
CTrainSAInterface* m_nextCarriage;
CDoorSAInterface m_aDoors[MAX_DOORS];
RwFrame* m_aTrainNodes[eTrainNode::NUM_NODES];
RwFrame* m_aTrainNodes[static_cast<std::size_t>(eTrainNodes::NUM_NODES)];
};
static_assert(sizeof(CTrainSAInterface) == 0x6AC, "Invalid size for CTrainSAInterface");

Expand Down
109 changes: 90 additions & 19 deletions Client/game_sa/CVehicleSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "CTrainSA.h"
#include "CPlaneSA.h"
#include "CVehicleSA.h"
#include "CBoatSA.h"
#include "CVisibilityPluginsSA.h"
#include "CWorldSA.h"
#include "gamesa_renderware.h"
Expand Down Expand Up @@ -1501,27 +1502,97 @@ void CVehicleSA::SetGravity(const CVector* pvecGravity)
m_vecGravity = *pvecGravity;
}

CObject* CVehicleSA::SpawnFlyingComponent(int i_1, unsigned int ui_2)
bool CVehicleSA::SpawnFlyingComponent(const eCarNodes& nodeIndex, const eCarComponentCollisionTypes& collisionType, std::int32_t removalTime)
{
DWORD dwReturn;
DWORD dwThis = (DWORD)GetInterface();
DWORD dwFunc = FUNC_CAutomobile__SpawnFlyingComponent;
_asm
if (nodeIndex == eCarNodes::NONE)
return false;

DWORD nodesOffset = OFFSET_CAutomobile_Nodes;
RwFrame* defaultBikeChassisFrame = nullptr;

// CBike, CBmx, CBoat and CTrain don't inherit CAutomobile so let's do it manually!
switch (static_cast<VehicleClass>(GetVehicleInterface()->m_vehicleClass))
{
mov ecx, dwThis
push ui_2
push i_1
call dwFunc
mov dwReturn, eax
case VehicleClass::AUTOMOBILE:
case VehicleClass::MONSTER_TRUCK:
case VehicleClass::PLANE:
case VehicleClass::HELI:
case VehicleClass::TRAILER:
case VehicleClass::QUAD:
{
nodesOffset = OFFSET_CAutomobile_Nodes;
break;
}
case VehicleClass::TRAIN:
{
if (static_cast<eTrainNodes>(nodeIndex) >= eTrainNodes::NUM_NODES)
return false;

nodesOffset = OFFSET_CTrain_Nodes;
break;
}
case VehicleClass::BIKE:
case VehicleClass::BMX:
{
auto* bikeInterface = static_cast<CBikeSAInterface*>(GetVehicleInterface());
if (!bikeInterface)
return false;

if (static_cast<eBikeNodes>(nodeIndex) >= eBikeNodes::NUM_NODES)
return false;

nodesOffset = OFFSET_CBike_Nodes;
if (static_cast<eBikeNodes>(nodeIndex) != eBikeNodes::CHASSIS)
break;

// Set the correct "bike_chassis" frame for bikes
defaultBikeChassisFrame = bikeInterface->m_apModelNodes[1];
if (defaultBikeChassisFrame && std::strcmp(defaultBikeChassisFrame->szName, "chassis_dummy") == 0)
{
RwFrame* correctChassisFrame = RwFrameFindFrame(RpGetFrame(bikeInterface->m_pRwObject), "chassis");
if (correctChassisFrame)
bikeInterface->m_apModelNodes[1] = correctChassisFrame;
}
break;
}
case VehicleClass::BOAT:
{
if (static_cast<eBoatNodes>(nodeIndex) >= eBoatNodes::NUM_NODES)
return false;

nodesOffset = OFFSET_CBoat_Nodes;
break;
}
default:
return false;
}

CObject* pObject = NULL;
if (dwReturn)
// Patch nodes array in CAutomobile::SpawnFlyingComponent
MemPut(0x6A85B3, nodesOffset);
MemPut(0x6A8631, nodesOffset);

auto* componentObject = ((CObjectSAInterface * (__thiscall*)(CVehicleSAInterface*, int, int)) FUNC_CAutomobile__SpawnFlyingComponent)(GetVehicleInterface(), static_cast<int>(nodeIndex), static_cast<int>(collisionType));

// Restore default nodes array in CAutomobile::SpawnFlyingComponent
// CAutomobile::m_aCarNodes offset
MemPut(0x6A85B3, 0x648);
MemPut(0x6A8631, 0x648);

// Restore default chassis frame for bikes
if (static_cast<eBikeNodes>(nodeIndex) == eBikeNodes::CHASSIS && defaultBikeChassisFrame)
{
SClientEntity<CObjectSA>* pObjectClientEntity = pGame->GetPools()->GetObject((DWORD*)dwReturn);
pObject = pObjectClientEntity ? pObjectClientEntity->pEntity : nullptr;
auto* bikeInterface = static_cast<CBikeSAInterface*>(GetVehicleInterface());
if (bikeInterface && bikeInterface->m_apModelNodes)
bikeInterface->m_apModelNodes[1] = defaultBikeChassisFrame;
}
return pObject;

if (removalTime <= -1 || !componentObject)
return true;

std::uint32_t CTimer_ms = *reinterpret_cast<std::uint32_t*>(VAR_CTimer_snTimeInMilliseconds);
componentObject->uiObjectRemovalTime = CTimer_ms + static_cast<std::uint32_t>(removalTime);

return true;
}

void CVehicleSA::SetWheelVisibility(eWheelPosition wheel, bool bVisible)
Expand All @@ -1531,16 +1602,16 @@ void CVehicleSA::SetWheelVisibility(eWheelPosition wheel, bool bVisible)
switch (wheel)
{
case FRONT_LEFT_WHEEL:
pFrame = vehicle->m_aCarNodes[eCarNode::WHEEL_LF];
pFrame = vehicle->m_aCarNodes[static_cast<std::size_t>(eCarNodes::WHEEL_LF)];
break;
case REAR_LEFT_WHEEL:
pFrame = vehicle->m_aCarNodes[eCarNode::WHEEL_LB];
pFrame = vehicle->m_aCarNodes[static_cast<std::size_t>(eCarNodes::WHEEL_LB)];
break;
case FRONT_RIGHT_WHEEL:
pFrame = vehicle->m_aCarNodes[eCarNode::WHEEL_RF];
pFrame = vehicle->m_aCarNodes[static_cast<std::size_t>(eCarNodes::WHEEL_RF)];
break;
case REAR_RIGHT_WHEEL:
pFrame = vehicle->m_aCarNodes[eCarNode::WHEEL_RB];
pFrame = vehicle->m_aCarNodes[static_cast<std::size_t>(eCarNodes::WHEEL_RB)];
break;
default:
break;
Expand Down
16 changes: 15 additions & 1 deletion Client/game_sa/CVehicleSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ struct RwTexture;
#define FUNC_CAutomobile_OnVehiclePreRender 0x6ABCFD
#define FUNC_CVehicle_DoSunGlare 0x6DD6F0

// CClumpModelInfo::GetFrameFromName
#define FUNC_CClumpModelInfo_GetFrameFromName 0x4C5400

// CAutomobile::m_aCarNodes
// CTrain::m_aTrainNodes
// CBike::m_apModelNodes
// CBoat::pBoatParts
#define OFFSET_CAutomobile_Nodes 0x648
#define OFFSET_CTrain_Nodes 0x668
#define OFFSET_CBike_Nodes 0x5A0
#define OFFSET_CBoat_Nodes 0x5B0

#define VAR_CTimer_snTimeInMilliseconds 0xB7CB84

struct SRailNodeSA
{
short sX; // x coordinate times 8
Expand Down Expand Up @@ -604,7 +618,7 @@ class CVehicleSA : public virtual CVehicle, public virtual CPhysicalSA
SharedUtil::SColor GetHeadLightColor() { return m_HeadLightColor; }
void SetHeadLightColor(const SharedUtil::SColor color) { m_HeadLightColor = color; }

CObject* SpawnFlyingComponent(int i_1, unsigned int ui_2);
bool SpawnFlyingComponent(const eCarNodes& nodeIndex, const eCarComponentCollisionTypes& collisionType, std::int32_t removalTime = -1);
void SetWheelVisibility(eWheelPosition wheel, bool bVisible);
CVector GetWheelPosition(eWheelPosition wheel);

Expand Down
8 changes: 8 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5037,6 +5037,14 @@ void CClientVehicle::ResetWheelScale()
m_bWheelScaleChanged = false;
}

bool CClientVehicle::SpawnFlyingComponent(const eCarNodes& nodeID, const eCarComponentCollisionTypes& collisionType, std::int32_t removalTime)
{
if (!m_pVehicle)
return false;

return m_pVehicle->SpawnFlyingComponent(nodeID, collisionType, removalTime);
}

CVector CClientVehicle::GetEntryPoint(std::uint32_t entryPointIndex)
{
static const uint32_t lookup[4] = {10, 8, 11, 9};
Expand Down
2 changes: 2 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,8 @@ class CClientVehicle : public CClientStreamElement
bool SetDummyPosition(eVehicleDummies dummy, const CVector& position);
bool ResetDummyPositions();

bool SpawnFlyingComponent(const eCarNodes& nodeID, const eCarComponentCollisionTypes& collisionType, std::int32_t removalTime);

CVector GetEntryPoint(std::uint32_t entryPointIndex);

protected:
Expand Down
Loading
Loading