diff --git a/Client/game_sa/CDamageManagerSA.cpp b/Client/game_sa/CDamageManagerSA.cpp index 98cd595d3c..2afed6eb3e 100644 --- a/Client/game_sa/CDamageManagerSA.cpp +++ b/Client/game_sa/CDamageManagerSA.cpp @@ -33,50 +33,60 @@ BYTE CDamageManagerSA::GetDoorStatus(eDoors bDoor) return NULL; } -VOID CDamageManagerSA::SetDoorStatus(eDoors bDoor, BYTE bDoorStatus) +VOID CDamageManagerSA::SetDoorStatus(eDoors bDoor, BYTE bDoorStatus, bool bFlyingComponent) { DEBUG_TRACE("VOID CDamageManagerSA::SetDoorStatus ( eDoors bDoor, BYTE bDoorStatus )"); if (bDoor < MAX_DOORS) { + unsigned char ucOldStatus = internalInterface->Door[bDoor]; // Different from before? - if (internalInterface->Door[bDoor] != bDoorStatus) + if (ucOldStatus != bDoorStatus) { + bool bOldBashed = ucOldStatus == DT_DOOR_BASHED || ucOldStatus == DT_DOOR_BASHED_AND_SWINGING_FREE; + bool bNewBashed = bDoorStatus == DT_DOOR_BASHED || bDoorStatus == DT_DOOR_BASHED_AND_SWINGING_FREE; + // Set it internalInterface->Door[bDoor] = bDoorStatus; - // Are we making it intact? - if (bDoorStatus == DT_DOOR_INTACT || bDoorStatus == DT_DOOR_SWINGING_FREE) + // Update door model (only if needed - this gonna shut the door) + if (bOldBashed != bNewBashed || bDoorStatus == DT_DOOR_MISSING || ucOldStatus == DT_DOOR_MISSING) { - // Grab the car node index for the given door id - static int s_iCarNodeIndexes[6] = {0x10, 0x11, 0x0A, 0x08, 0x0B, 0x09}; - - // Call CAutomobile::FixDoor to update the model - DWORD dwFunc = 0x6A35A0; - DWORD dwThis = (DWORD)internalEntityInterface; - int iCarNodeIndex = s_iCarNodeIndexes[bDoor]; - DWORD dwDoor = (DWORD)bDoor; - _asm + // Fix it + if (bDoorStatus == DT_DOOR_INTACT || bDoorStatus == DT_DOOR_SWINGING_FREE) { - mov ecx, dwThis - push dwDoor - push iCarNodeIndex - call dwFunc + // Grab the car node index for the given door id + static int s_iCarNodeIndexes[6] = {0x10, 0x11, 0x0A, 0x08, 0x0B, 0x09}; + + // Call CAutomobile::FixDoor to update the model + DWORD dwFunc = 0x6A35A0; + DWORD dwThis = (DWORD)internalEntityInterface; + int iCarNodeIndex = s_iCarNodeIndexes[bDoor]; + DWORD dwDoor = (DWORD)bDoor; + _asm + { + mov ecx, dwThis + push dwDoor + push iCarNodeIndex + call dwFunc + } } - } - else - { - // Call CAutomobile::SetDoorDamage to update the model - DWORD dwFunc = 0x6B1600; - DWORD dwThis = (DWORD)internalEntityInterface; - DWORD dwDoor = (DWORD)bDoor; - bool bUnknown = false; - _asm + + // Broke it + if (bNewBashed || bDoorStatus == DT_DOOR_MISSING || ucOldStatus == DT_DOOR_MISSING) { - mov ecx, dwThis - push bUnknown - push dwDoor - call dwFunc + // Call CAutomobile::SetDoorDamage to update the model + DWORD dwFunc = 0x6B1600; + DWORD dwThis = (DWORD)internalEntityInterface; + DWORD dwDoor = (DWORD)bDoor; + bool bNoFlyingComponent = !bFlyingComponent; + _asm + { + mov ecx, dwThis + push bNoFlyingComponent + push dwDoor + call dwFunc + } } } } @@ -104,7 +114,7 @@ VOID CDamageManagerSA::SetWheelStatus(eWheelPosition bWheel, BYTE bTireStatus) } } -VOID CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) +VOID CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool bFlyingComponent) { DEBUG_TRACE("BYTE CDamageManagerSA::SetPanelStatus ( BYTE bLight, BYTE bPanelStatus )"); @@ -150,11 +160,16 @@ VOID CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) // Call CAutomobile::SetPanelDamage to update the vehicle dwFunction = 0x6B1480; dwThis = (DWORD)internalEntityInterface; - bool bUnknown = false; + bool bNoFlyingComponent = !bFlyingComponent; + if (bPanel == WINDSCREEN_PANEL) + { + bNoFlyingComponent = bFlyingComponent; + } + _asm { mov ecx, dwThis - push bUnknown + push bNoFlyingComponent push dwPanel call dwFunction } @@ -163,13 +178,13 @@ VOID CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) } } -void CDamageManagerSA::SetPanelStatus(unsigned long ulStatus) +void CDamageManagerSA::SetPanelStatus(unsigned long ulStatus, bool bFlyingComponent) { unsigned int uiIndex; for (uiIndex = 0; uiIndex < MAX_PANELS; uiIndex++) { - SetPanelStatus(static_cast(uiIndex), static_cast(ulStatus)); + SetPanelStatus(static_cast(uiIndex), static_cast(ulStatus), bFlyingComponent); ulStatus >>= 4; } } diff --git a/Client/game_sa/CDamageManagerSA.h b/Client/game_sa/CDamageManagerSA.h index 32a40e12f1..06d20877d1 100644 --- a/Client/game_sa/CDamageManagerSA.h +++ b/Client/game_sa/CDamageManagerSA.h @@ -9,8 +9,7 @@ * *****************************************************************************/ -#ifndef __CGAMESA_DAMAGEMANAGER -#define __CGAMESA_DAMAGEMANAGER +#pragma once #include #include "Common.h" @@ -55,13 +54,13 @@ class CDamageManagerSA : public CDamageManager BYTE GetEngineStatus(); VOID SetEngineStatus(BYTE bEngineState); BYTE GetDoorStatus(eDoors bDoor); - VOID SetDoorStatus(eDoors bDoor, BYTE bDoorStatus); + VOID SetDoorStatus(eDoors bDoor, BYTE bDoorStatus, bool bFlyingComponent = true); BYTE GetWheelStatus(eWheelPosition bWheel); VOID SetWheelStatus(eWheelPosition bWheel, BYTE bTireStatus); BYTE GetPanelStatus(BYTE bPanel); unsigned long GetPanelStatus(void); - VOID SetPanelStatus(BYTE bPanel, BYTE bPanelStatus); - void SetPanelStatus(unsigned long ulStatus); + VOID SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool bFlyingComponent = true); + void SetPanelStatus(unsigned long ulStatus, bool bFlyingComponent = true); BYTE GetLightStatus(BYTE bLight); unsigned char GetLightStatus(void); VOID SetLightStatus(BYTE bLight, BYTE bLightStatus); @@ -77,5 +76,3 @@ class CDamageManagerSA : public CDamageManager internalInterface = intInterface; }; }; - -#endif diff --git a/Client/game_sa/CDoorSA.h b/Client/game_sa/CDoorSA.h index c72e37997f..c52a686375 100644 --- a/Client/game_sa/CDoorSA.h +++ b/Client/game_sa/CDoorSA.h @@ -9,8 +9,7 @@ * *****************************************************************************/ -#ifndef __CGAMESA_DOOR -#define __CGAMESA_DOOR +#pragma once #include #include @@ -62,6 +61,5 @@ class CDoorSA : public CDoor BOOL IsFullyOpen(); VOID Open(float fOpenRatio); eDoorState GetDoorState() { return (eDoorState)this->GetInterface()->m_nDoorState; }; + void SetDoorState(unsigned char ucState) { GetInterface()->m_nDoorState = ucState; }; }; - -#endif diff --git a/Client/mods/deathmatch/logic/CClientPed.cpp b/Client/mods/deathmatch/logic/CClientPed.cpp index 44796b606e..1ede065618 100644 --- a/Client/mods/deathmatch/logic/CClientPed.cpp +++ b/Client/mods/deathmatch/logic/CClientPed.cpp @@ -1538,7 +1538,10 @@ CClientVehicle* CClientPed::RemoveFromVehicle(bool bSkipWarpIfGettingOut) if (pVehicle) { - pVehicle->SetSwingingDoorsAllowed(false); + if (m_bIsLocalPlayer) + { + pVehicle->SetSwingingDoorsAllowed(false); + } // Warp the player out of the vehicle CVehicle* pGameVehicle = pVehicle->m_pVehicle; diff --git a/Client/mods/deathmatch/logic/CClientVehicle.cpp b/Client/mods/deathmatch/logic/CClientVehicle.cpp index d14d29fc7f..2fa8f3a962 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicle.cpp @@ -654,8 +654,6 @@ void CClientVehicle::ProcessDoorInterpolation() void CClientVehicle::SetDoorOpenRatio(unsigned char ucDoor, float fRatio, unsigned long ulDelay, bool bForced) { - unsigned char ucSeat; - if (ucDoor <= 5) { bool bAllow = m_bAllowDoorRatioSetting[ucDoor]; @@ -663,17 +661,22 @@ void CClientVehicle::SetDoorOpenRatio(unsigned char ucDoor, float fRatio, unsign // Prevent setting the door angle ratio while a ped is entering/leaving the vehicle. if (bAllow && bForced == false) { - switch (ucDoor) + CClientPed * pPed = GetOccupyingPed(ucDoor - 2); + if (pPed) { - case 2: - bAllow = m_pOccupyingDriver == 0; - break; - case 3: - case 4: - case 5: - ucSeat = ucDoor - 2; - bAllow = m_pOccupyingPassengers[ucSeat] == 0; - break; + // Don't change angle if somebody is messing with this door + // Allow critical values like fully closed or open. + bAllow = !pPed->IsGettingIntoVehicle() || fRatio == 0 || fRatio == 1; + + /* + Driver closing door minor desync: + + Player enters a car which has already open driver door (he enters via passenger side or warpPedIntoVehicle). + He closes the door and sends new ratio to other clients. + But other clients are also closing this door which causes ugly effect. + + TODO: Find a way to detect if ped is closing door. + */ } } @@ -825,13 +828,13 @@ void CClientVehicle::Fix(void) SFixedArray ucDoorStates; GetInitialDoorStates(ucDoorStates); for (int i = 0; i < MAX_DOORS; i++) - SetDoorStatus(i, ucDoorStates[i]); - for (int i = 0; i < MAX_PANELS; i++) - SetPanelStatus(i, 0); - for (int i = 0; i < MAX_LIGHTS; i++) - SetLightStatus(i, 0); - for (int i = 0; i < MAX_WHEELS; i++) - SetWheelStatus(i, 0); + { + SetDoorStatus(i, ucDoorStates[i], false); + SetDoorOpenRatio(i, 0, 0, true); + } + for (int i = 0; i < MAX_PANELS; i++) SetPanelStatus(i, 0, false); + for (int i = 0; i < MAX_LIGHTS; i++) SetLightStatus(i, 0); + for (int i = 0; i < MAX_WHEELS; i++) SetWheelStatus(i, 0); // These components get a funny rotation when calling Fix() (unknown reason) struct @@ -1471,13 +1474,59 @@ unsigned char CClientVehicle::GetLightStatus(unsigned char ucLight) return 0; } -void CClientVehicle::SetDoorStatus(unsigned char ucDoor, unsigned char ucStatus) +// Helpers for dealing with door ajar status without chance to accidently broke bashed status +void CClientVehicle::SetDoorAjarStatus(unsigned char ucDoor, bool bAjar) +{ + unsigned char ucStatus = GetDoorStatus(ucDoor); + if (ucStatus != DT_DOOR_MISSING) + { + unsigned char ucNewStatus; + if (ucStatus == DT_DOOR_INTACT || ucStatus == DT_DOOR_SWINGING_FREE) + { + ucNewStatus = bAjar; + } + else if (ucStatus == DT_DOOR_BASHED || ucStatus == DT_DOOR_BASHED_AND_SWINGING_FREE) + { + ucNewStatus = bAjar + 2; + } + SetDoorStatus(ucDoor, ucNewStatus, false); + } +} + +bool CClientVehicle::GetDoorAjarStatus(unsigned char ucDoor) +{ + unsigned char ucStatus = GetDoorStatus(ucDoor); + if (ucStatus == DT_DOOR_MISSING) + { + // Let's say they are ajar but this really shouldn't be used without checking if they are missing first + return true; + } + return ucStatus == DT_DOOR_SWINGING_FREE || ucStatus == DT_DOOR_BASHED_AND_SWINGING_FREE; +} + +void CClientVehicle::SetDoorStatus(unsigned char ucDoor, unsigned char ucStatus, bool bFlyingComponent) { if (ucDoor < MAX_DOORS) { if (m_pVehicle && HasDamageModel()) { - m_pVehicle->GetDamageManager()->SetDoorStatus(static_cast(ucDoor), ucStatus); + if (ucStatus == DT_DOOR_BASHED_AND_SWINGING_FREE) + { + // Set it to bashed first + SetDoorStatus(ucDoor, DT_DOOR_BASHED, bFlyingComponent); + } + else if (ucStatus == DT_DOOR_SWINGING_FREE) + { + // Set it to intact first + SetDoorStatus(ucDoor, DT_DOOR_INTACT, bFlyingComponent); + } + + m_pVehicle->GetDamageManager()->SetDoorStatus(static_cast(ucDoor), ucStatus, bFlyingComponent); + CDoor* pDoor = m_pVehicle->GetDoor(ucDoor); + if (pDoor) + { + pDoor->SetDoorState(ucStatus); + } } m_ucDoorStates[ucDoor] = ucStatus; } @@ -1543,13 +1592,13 @@ bool CClientVehicle::GetWheelMissing(unsigned char ucWheel, const SString& strWh return false; } -void CClientVehicle::SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus) +void CClientVehicle::SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus, bool bSpawnComponent) { if (ucPanel < MAX_PANELS) { if (m_pVehicle && HasDamageModel()) { - m_pVehicle->GetDamageManager()->SetPanelStatus(static_cast(ucPanel), ucStatus); + m_pVehicle->GetDamageManager()->SetPanelStatus(static_cast(ucPanel), ucStatus, bSpawnComponent); } m_ucPanelStates[ucPanel] = ucStatus; } @@ -1683,6 +1732,20 @@ CClientPed* CClientVehicle::GetOccupant(int iSeat) const return NULL; } +// Returns ped which is TRYING to get this seat. +CClientPed* CClientVehicle::GetOccupyingPed(unsigned char uiSeat) const +{ + if (uiSeat == 0) + { + return (CClientPed*)(const CClientPed*)m_pOccupyingDriver; + } + else if (uiSeat <= (sizeof(m_pOccupyingPassengers) / sizeof(CClientPed*))) + { + return m_pOccupyingPassengers[uiSeat - 1]; + } + return NULL; +} + CClientPed* CClientVehicle::GetControllingPlayer(void) { CClientPed* pControllingPlayer = m_pDriver; @@ -2184,9 +2247,13 @@ void CClientVehicle::StreamedInPulse(void) CDamageManager* pDamageManager = m_pVehicle->GetDamageManager(); for (int i = 0; i < MAX_DOORS; i++) - pDamageManager->SetDoorStatus(static_cast(i), m_ucDoorStates[i]); + { + float fRatio = GetDoorOpenRatio(i); + SetDoorStatus(i, m_ucDoorStates[i], false); + SetDoorOpenRatio(i, fRatio, 0, true); + } for (int i = 0; i < MAX_PANELS; i++) - pDamageManager->SetPanelStatus(static_cast(i), m_ucPanelStates[i]); + pDamageManager->SetPanelStatus(static_cast(i), m_ucPanelStates[i], false); for (int i = 0; i < MAX_LIGHTS; i++) pDamageManager->SetLightStatus(static_cast(i), m_ucLightStates[i]); } diff --git a/Client/mods/deathmatch/logic/CClientVehicle.h b/Client/mods/deathmatch/logic/CClientVehicle.h index d76cceebc2..2961bc8bff 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.h +++ b/Client/mods/deathmatch/logic/CClientVehicle.h @@ -253,16 +253,18 @@ class CClientVehicle : public CClientStreamElement public: bool HasDamageModel(void) { return m_bHasDamageModel; } unsigned char GetDoorStatus(unsigned char ucDoor); + bool GetDoorAjarStatus(unsigned char ucDoor); unsigned char GetWheelStatus(unsigned char ucWheel); - bool IsWheelCollided(unsigned char ucWheel); unsigned char GetPanelStatus(unsigned char ucPanel); unsigned char GetLightStatus(unsigned char ucLight); + bool IsWheelCollided(unsigned char ucWheel); + bool GetWheelMissing(unsigned char ucWheel, const SString& strWheelName = ""); - void SetDoorStatus(unsigned char ucDoor, unsigned char ucStatus); + void SetDoorStatus(unsigned char ucDoor, unsigned char ucStatus, bool bFlyingComponent = true); + void SetDoorAjarStatus(unsigned char ucDoor, bool bAjar); void SetWheelStatus(unsigned char ucWheel, unsigned char ucStatus, bool bSilent = true); - void SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus); + void SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus, bool bFlyingComponent = true); void SetLightStatus(unsigned char ucLight, unsigned char ucStatus); - bool GetWheelMissing(unsigned char ucWheel, const SString& strWheelName = ""); // TODO: Make the class remember on virtualization float GetHeliRotorSpeed(void); @@ -286,6 +288,7 @@ class CClientVehicle : public CClientStreamElement void SetAlpha(unsigned char ucAlpha); CClientPed* GetOccupant(int iSeat = 0) const; + CClientPed* GetOccupyingPed(unsigned char uiSeat) const; CClientPed* GetControllingPlayer(void); void ClearForOccupants(void); diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 75d6973644..6ab5c3ced6 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -1635,12 +1635,25 @@ void CPacketHandler::Packet_Vehicle_InOut(NetBitStreamInterface& bitStream) case CClientGame::VEHICLE_NOTIFY_IN_RETURN: { + bool bEnteringThis = pPlayer->IsGettingIntoVehicle() && pVehicle == pPlayer->m_pOccupyingVehicle; + if (!pPlayer->IsLocalPlayer() || pPlayer->GetOccupiedVehicle() != pVehicle) { // Warp him in. Don't do that for local player as he is already sitting inside. pPlayer->WarpIntoVehicle(pVehicle, ucSeat); } + if ( bEnteringThis ) + { + // WarpIntoVehicle can premature kill entering task which can freeze door mid-closing + // So shut the door + float fRatio = pVehicle->GetDoorOpenRatio ( pPlayer->m_ucEnteringDoor ); + if ( fRatio > 0 ) + { + pVehicle->SetDoorOpenRatio ( pPlayer->m_ucEnteringDoor, 0, 0, true ); + } + } + // Reset vehicle in out state pPlayer->SetVehicleInOutState(VEHICLE_INOUT_NONE); @@ -1904,6 +1917,13 @@ void CPacketHandler::Packet_Vehicle_InOut(NetBitStreamInterface& bitStream) { g_pClientGame->m_bIsGettingJacked = false; g_pClientGame->m_bIsJackingVehicle = false; + + // Fix driver door ajar state if he jacked from passenger side + // so he will be able to close it + if ( pInsidePlayer->m_ucEnteringDoor == 3 && pVehicle->GetDoorAjarStatus ( 2 ) == false ) + { + pVehicle->SetDoorAjarStatus ( 2, true ); + } } // Reset vehicle in out state diff --git a/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp index c8e5fc196f..1d1eda322e 100644 --- a/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CPedRPCs.cpp @@ -199,6 +199,27 @@ void CPedRPCs::WarpPedIntoVehicle(CClientEntity* pSource, NetBitStreamInterface& if (pVehicle) { CStaticFunctionDefinitions::WarpPedIntoVehicle(pPed, pVehicle, ucSeat); + + // Driver seat? + if (ucSeat == 0) + { + // Driver door open? + if (pVehicle->GetDoorStatus(2) != DT_DOOR_MISSING && pVehicle->GetDoorOpenRatio(2) > 0) + { + if (pPed->IsLocalPlayer()) + { + // Fix driver door ajar state so player will be able to close it + pVehicle->SetDoorAjarStatus(2, true); + } + else + { + // Do otherwise so remotes won't see it closing (it will come from syncer) + // (however this creates ugly effect because doors move but there is no closing door animation) + // TODO: remove this when closing door check will be added to CClientVehicle::SetDoorOpenRatio + pVehicle->SetDoorAjarStatus( 2, false); + } + } + } } } } diff --git a/Client/sdk/game/CDamageManager.h b/Client/sdk/game/CDamageManager.h index 5d19f5afca..04b7aec2b7 100644 --- a/Client/sdk/game/CDamageManager.h +++ b/Client/sdk/game/CDamageManager.h @@ -9,8 +9,7 @@ * *****************************************************************************/ -#ifndef __CGAME_DAMAGEMANAGER -#define __CGAME_DAMAGEMANAGER +#pragma once #include @@ -131,13 +130,13 @@ class CDamageManager virtual BYTE GetEngineStatus(void) = 0; virtual VOID SetEngineStatus(BYTE bEngineState) = 0; virtual BYTE GetDoorStatus(eDoors bDoor) = 0; - virtual VOID SetDoorStatus(eDoors bDoor, BYTE bDoorStatus) = 0; + virtual VOID SetDoorStatus(eDoors bDoor, BYTE bDoorStatus, bool bSpawnComponent = true) = 0; virtual BYTE GetWheelStatus(eWheelPosition bTire) = 0; virtual VOID SetWheelStatus(eWheelPosition bTire, BYTE bTireStatus) = 0; virtual BYTE GetPanelStatus(BYTE bPanel) = 0; virtual unsigned long GetPanelStatus(void) = 0; - virtual VOID SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) = 0; - virtual void SetPanelStatus(unsigned long ulStatus) = 0; + virtual VOID SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool bSpawnComponent = true) = 0; + virtual void SetPanelStatus(unsigned long ulStatus, bool bSpawnComponent = true) = 0; virtual BYTE GetLightStatus(BYTE bLight) = 0; virtual unsigned char GetLightStatus(void) = 0; virtual VOID SetLightStatus(BYTE bLight, BYTE bLightStatus) = 0; @@ -147,5 +146,3 @@ class CDamageManager virtual VOID FuckCarCompletely(BOOL bKeepWheels) = 0; }; - -#endif diff --git a/Client/sdk/game/CDoor.h b/Client/sdk/game/CDoor.h index 4f5cd50610..a5c2eb7bdf 100644 --- a/Client/sdk/game/CDoor.h +++ b/Client/sdk/game/CDoor.h @@ -9,8 +9,7 @@ * *****************************************************************************/ -#ifndef __CGAME_DOOR -#define __CGAME_DOOR +#pragma once #include @@ -24,6 +23,5 @@ class CDoor virtual BOOL IsFullyOpen() = 0; virtual VOID Open(float fRatio) = 0; virtual eDoorState GetDoorState() = 0; + virtual void SetDoorState(unsigned char ucState) = 0; }; - -#endif