Skip to content
Merged
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
2 changes: 2 additions & 0 deletions Client/game_sa/CGameSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ class CGameSA : public CGame
bool IsVehicleBurnExplosionsEnabled() const noexcept override { return m_isVehicleBurnExplosionsEnabled; }
void SetVehicleBurnExplosionsEnabled(bool isEnabled) override;

bool IsVehicleEngineManualModeEnabled() const noexcept override { return *(unsigned char*)0x64BC03 == 0x90; }

unsigned long GetMinuteDuration();
void SetMinuteDuration(unsigned long ulTime);

Expand Down
28 changes: 27 additions & 1 deletion Client/game_sa/CVehicleSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,39 @@ void _declspec(naked) HOOK_Vehicle_PreRender(void)
}
}

float& fTimeStep = *(float*)(0xB7CB5C);
static bool __fastcall CanProcessFlyingCarStuff(CAutomobileSAInterface* vehicleInterface)
{
SClientEntity<CVehicleSA>* vehicle = pGame->GetPools()->GetVehicle((DWORD*)vehicleInterface);
if (!vehicle || !vehicle->pEntity)
return true;

return vehicle->pEntity->GetVehicleRotorState();
if (vehicle->pEntity->GetVehicleRotorState())
{
if (!pGame->IsVehicleEngineManualModeEnabled()) // keep default behavior
return true;

if (vehicle->pEntity->GetEntityStatus() != eEntityStatus::STATUS_PHYSICS && !vehicle->pEntity->IsBeingDriven())
{
vehicle->pEntity->SetEntityStatus(eEntityStatus::STATUS_PHYSICS); // this will make rotors spin without driver when engine is on
return false;
}
if (!vehicle->pEntity->IsEngineOn())
{
// Smoothly change rotors speed to 0
float speed = vehicle->pEntity->GetHeliRotorSpeed();
if (speed > 0)
vehicle->pEntity->SetHeliRotorSpeed(std::max(0.0f, speed - fTimeStep * 0.00055f)); // 0x6C4EB7

speed = vehicle->pEntity->GetPlaneRotorSpeed();
if (speed > 0)
vehicle->pEntity->SetPlaneRotorSpeed(std::max(0.0f, speed - fTimeStep * 0.003f)); // 0x6CC145

return false;
}
return true;
}
return false;
}

static constexpr DWORD CONTINUE_CHeli_ProcessFlyingCarStuff = 0x6C4E82;
Expand Down
20 changes: 20 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6057,6 +6057,9 @@ bool CClientGame::SetWorldSpecialProperty(const WorldSpecialProperty property, c
case WorldSpecialProperty::VEHICLEBURNEXPLOSIONS:
g_pGame->SetVehicleBurnExplosionsEnabled(enabled);
break;
case WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE:
SetVehicleEngineManualModeEnabled(enabled);
break;
default:
return false;
}
Expand Down Expand Up @@ -6103,6 +6106,8 @@ bool CClientGame::IsWorldSpecialProperty(const WorldSpecialProperty property)
return m_pVehicleManager->IsSpawnFlyingComponentEnabled();
case WorldSpecialProperty::VEHICLEBURNEXPLOSIONS:
return g_pGame->IsVehicleBurnExplosionsEnabled();
case WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE:
return IsVehicleEngineManualModeEnabled();
}

return false;
Expand Down Expand Up @@ -6138,6 +6143,20 @@ bool CClientGame::IsWeaponRenderEnabled() const
return g_pGame->IsWeaponRenderEnabled();
}

void CClientGame::SetVehicleEngineManualModeEnabled(bool enabled)
{
if (enabled == g_pGame->IsVehicleEngineManualModeEnabled())
return;

g_pMultiplayer->SetVehicleEngineManualModeEnabled(enabled);
m_pVehicleManager->ResetNotControlledRotors(enabled);
}

bool CClientGame::IsVehicleEngineManualModeEnabled() const
{
return g_pGame->IsVehicleEngineManualModeEnabled();
}

#pragma code_seg(".text")
bool CClientGame::VerifySADataFiles(int iEnableClientChecks)
{
Expand Down Expand Up @@ -6823,6 +6842,7 @@ void CClientGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo
g_pGame->SetIgnoreFireStateEnabled(false);
m_pVehicleManager->SetSpawnFlyingComponentEnabled(true);
g_pGame->SetVehicleBurnExplosionsEnabled(true);
SetVehicleEngineManualModeEnabled(false);
}

// Reset all setWorldProperty to default
Expand Down
3 changes: 3 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@ class CClientGame
void SetWeaponRenderEnabled(bool enabled);
bool IsWeaponRenderEnabled() const;

void SetVehicleEngineManualModeEnabled(bool enabled);
bool IsVehicleEngineManualModeEnabled() const;

void ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo);

CTransferBox* GetTransferBox() { return m_pTransferBox; };
Expand Down
17 changes: 17 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,3 +791,20 @@ void CClientVehicleManager::RestreamVehicleUpgrades(unsigned short usModel)
pVehicle->GetUpgrades()->RestreamVehicleUpgrades(usModel);
}
}

void CClientVehicleManager::ResetNotControlledRotors(bool isManualMode)
{
// Reset rotors to custom or original state for loaded vehicles without controller
// Custom state allows rotors to spin without driver inside (if engine is on)
eEntityStatus status = isManualMode ? eEntityStatus::STATUS_PHYSICS : eEntityStatus::STATUS_ABANDONED;
for (auto& pVehicle : m_List)
{
if (pVehicle->GetGameEntity() && pVehicle->GetVehicleRotorState() && !pVehicle->IsDriven())
{
float speed = (isManualMode && pVehicle->IsEngineOn()) ? 0.001f : 0.0f;
pVehicle->GetGameEntity()->SetEntityStatus(status);
pVehicle->SetHeliRotorSpeed(speed);
pVehicle->SetPlaneRotorSpeed(speed);
}
}
}
2 changes: 2 additions & 0 deletions Client/mods/deathmatch/logic/CClientVehicleManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class CClientVehicleManager
bool IsSpawnFlyingComponentEnabled() const noexcept { return m_spawnFlyingComponentsDuringRecreate; }
void SetSpawnFlyingComponentEnabled(bool isEnabled) noexcept { m_spawnFlyingComponentsDuringRecreate = isEnabled; }

void ResetNotControlledRotors(bool isManualMode);

protected:
CClientManager* m_pManager;
bool m_bCanRemoveFromList;
Expand Down
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CPacketHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2402,6 +2402,7 @@ void CPacketHandler::Packet_MapInfo(NetBitStreamInterface& bitStream)
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::IGNOREFIRESTATE, wsProps.data6.ignoreFireState);
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::FLYINGCOMPONENTS, wsProps.data7.flyingcomponents);
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, wsProps.data8.vehicleburnexplosions);
g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE, wsProps.data9.vehEngineManualMode);

float fJetpackMaxHeight = 100;
if (!bitStream.Read(fJetpackMaxHeight))
Expand Down
14 changes: 14 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6634,6 +6634,20 @@ void CMultiplayerSA::SetAutomaticVehicleStartupOnPedEnter(bool bSet)
MemSet((char*)0x64BC0D, 0x90, 6);
}

void CMultiplayerSA::SetVehicleEngineManualModeEnabled(bool enabled)
{
if (enabled)
{
MemSet((void*)0x64BC03, 0x90, 5); // prevent vehicle engine from turning on (driver enter)
MemCpy((void*)0x6C4EA9, "\xE9\x15\x03\x00", 4); // prevent aircraft engine from turning off (driver exit)
}
else
{
MemCpy((void*)0x64BC03, "\x75\x05\x80\xC9\x10", 5);
MemCpy((void*)0x6C4EA9, "\x8A\x86\x28\x04", 4);
}
}

// Storage
CVehicleSAInterface* pHeliKiller = NULL;
CEntitySAInterface* pHitByHeli = NULL;
Expand Down
2 changes: 2 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ class CMultiplayerSA : public CMultiplayer

void SetAutomaticVehicleStartupOnPedEnter(bool bSet);

void SetVehicleEngineManualModeEnabled(bool enabled) override;

void SetPedTargetingMarkerEnabled(bool bEnable);
bool IsPedTargetingMarkerEnabled();
bool IsConnected();
Expand Down
2 changes: 2 additions & 0 deletions Client/sdk/game/CGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ class __declspec(novtable) CGame
virtual bool IsVehicleBurnExplosionsEnabled() const noexcept = 0;
virtual void SetVehicleBurnExplosionsEnabled(bool isEnabled) = 0;

virtual bool IsVehicleEngineManualModeEnabled() const noexcept = 0;

virtual CWeapon* CreateWeapon() = 0;
virtual CWeaponStat* CreateWeaponStat(eWeaponType weaponType, eWeaponSkill weaponSkill) = 0;

Expand Down
2 changes: 2 additions & 0 deletions Client/sdk/multiplayer/CMultiplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,8 @@ class CMultiplayer

virtual void SetAutomaticVehicleStartupOnPedEnter(bool bSet) = 0;

virtual void SetVehicleEngineManualModeEnabled(bool enabled) = 0;

virtual void SetPedTargetingMarkerEnabled(bool bEnabled) = 0;
virtual bool IsPedTargetingMarkerEnabled() = 0;

Expand Down
5 changes: 4 additions & 1 deletion Server/mods/deathmatch/logic/CGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ CGame::CGame() : m_FloodProtect(4, 30000, 30000) // Max of 4 connecti
m_WorldSpecialProps[WorldSpecialProperty::IGNOREFIRESTATE] = false;
m_WorldSpecialProps[WorldSpecialProperty::FLYINGCOMPONENTS] = true;
m_WorldSpecialProps[WorldSpecialProperty::VEHICLEBURNEXPLOSIONS] = true;
m_WorldSpecialProps[WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE] = false;

m_JetpackWeapons[WEAPONTYPE_MICRO_UZI] = true;
m_JetpackWeapons[WEAPONTYPE_TEC9] = true;
Expand Down Expand Up @@ -3405,7 +3406,8 @@ void CGame::Packet_Vehicle_InOut(CVehicleInOutPacket& Packet)
pPed->SetVehicleAction(CPed::VEHICLEACTION_NONE);

// Update our engine State
pVehicle->SetEngineOn(true);
if (!g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE))
pVehicle->SetEngineOn(true);

// Tell everyone he's in (they should warp him in)
CVehicleInOutPacket Reply(PedID, VehicleID, ucOccupiedSeat, VEHICLE_NOTIFY_IN_RETURN);
Expand Down Expand Up @@ -4524,6 +4526,7 @@ void CGame::ResetWorldProperties(const ResetWorldPropsInfo& resetPropsInfo)
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::IGNOREFIRESTATE, false);
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS, true);
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, true);
g_pGame->SetWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE, false);
}

// Reset all weather stuff like heat haze, wind velocity etc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4262,7 +4262,7 @@ bool CStaticFunctionDefinitions::WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehic
pPed->SetVehicleAction(CPed::VEHICLEACTION_NONE);

// If he's the driver, switch on the engine
if (uiSeat == 0)
if (uiSeat == 0 && !g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE))
pVehicle->SetEngineOn(true);

// Tell all the players
Expand Down
1 change: 1 addition & 0 deletions Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ bool CMapInfoPacket::Write(NetBitStreamInterface& BitStream) const
wsProps.data6.ignoreFireState = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::IGNOREFIRESTATE);
wsProps.data7.flyingcomponents = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::FLYINGCOMPONENTS);
wsProps.data8.vehicleburnexplosions = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS);
wsProps.data9.vehEngineManualMode = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE);
BitStream.Write(&wsProps);
}

Expand Down
1 change: 1 addition & 0 deletions Shared/mods/deathmatch/logic/Enums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ ADD_ENUM(WorldSpecialProperty::TUNNELWEATHERBLEND, "tunnelweatherblend")
ADD_ENUM(WorldSpecialProperty::IGNOREFIRESTATE, "ignorefirestate")
ADD_ENUM(WorldSpecialProperty::FLYINGCOMPONENTS, "flyingcomponents")
ADD_ENUM(WorldSpecialProperty::VEHICLEBURNEXPLOSIONS, "vehicleburnexplosions")
ADD_ENUM(WorldSpecialProperty::VEHICLE_ENGINE_MANUAL_MODE, "vehenginemanualmode")
IMPLEMENT_ENUM_CLASS_END("world-special-property")

IMPLEMENT_ENUM_BEGIN(ePacketID)
Expand Down
1 change: 1 addition & 0 deletions Shared/mods/deathmatch/logic/Enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ enum class WorldSpecialProperty
IGNOREFIRESTATE,
FLYINGCOMPONENTS,
VEHICLEBURNEXPLOSIONS,
VEHICLE_ENGINE_MANUAL_MODE,
};
DECLARE_ENUM_CLASS(WorldSpecialProperty);

Expand Down
18 changes: 18 additions & 0 deletions Shared/sdk/net/SyncStructures.h
Original file line number Diff line number Diff line change
Expand Up @@ -2083,6 +2083,10 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
{
BITCOUNT8 = 1
};
enum
{
BITCOUNT9 = 1
};

bool Read(NetBitStreamInterface& bitStream)
{
Expand Down Expand Up @@ -2121,6 +2125,11 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
isOK &= bitStream.ReadBits(reinterpret_cast<char*>(&data8), BITCOUNT8);
else
data8.vehicleburnexplosions = true;

if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleEngineManualMode))
isOK &= bitStream.ReadBits(reinterpret_cast<char*>(&data9), BITCOUNT9);
else
data9.vehEngineManualMode = false;

//// Example for adding item:
// if (bitStream.Can(eBitStreamVersion::YourProperty))
Expand Down Expand Up @@ -2154,6 +2163,9 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleBurnExplosions))
bitStream.WriteBits(reinterpret_cast<const char*>(&data8), BITCOUNT8);

if (bitStream.Can(eBitStreamVersion::WorldSpecialProperty_VehicleEngineManualMode))
bitStream.WriteBits(reinterpret_cast<const char*>(&data9), BITCOUNT9);

//// Example for adding item:
// if (bitStream.Can(eBitStreamVersion::YourProperty))
// bitStream.WriteBits(reinterpret_cast<const char*>(&data9), BITCOUNT9);
Expand Down Expand Up @@ -2210,6 +2222,11 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
{
bool vehicleburnexplosions : 1;
} data8;

struct
{
bool vehEngineManualMode : 1;
} data9;

SWorldSpecialPropertiesStateSync()
{
Expand All @@ -2233,6 +2250,7 @@ struct SWorldSpecialPropertiesStateSync : public ISyncStructure
data6.ignoreFireState = false;
data7.flyingcomponents = true;
data8.vehicleburnexplosions = true;
data9.vehEngineManualMode = false;
}
};

Expand Down
4 changes: 4 additions & 0 deletions Shared/sdk/net/bitstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,10 @@ enum class eBitStreamVersion : unsigned short
// 2025-05-26
ServersideBuildingElement,

// Add "vehenginemanualmode" to setWorldSpecialPropertyEnabled
// 2025-05-29
WorldSpecialProperty_VehicleEngineManualMode,

// This allows us to automatically increment the BitStreamVersion when things are added to this enum.
// Make sure you only add things above this comment.
Next,
Expand Down
Loading