2014-08-03 15:38:53 +02:00
|
|
|
#include "StdAfxSA.h"
|
2014-05-30 20:14:47 +02:00
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
#include <functional>
|
2016-11-12 18:28:46 +01:00
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
2014-08-03 15:38:53 +02:00
|
|
|
#include "VehicleSA.h"
|
|
|
|
#include "TimerSA.h"
|
2017-03-23 11:30:06 +01:00
|
|
|
#include "DelimStringReader.h"
|
2014-05-30 20:14:47 +02:00
|
|
|
|
2017-04-09 18:13:52 +02:00
|
|
|
std::vector<uint32_t> vecRotorExceptions;
|
2016-11-12 18:28:46 +01:00
|
|
|
|
2017-04-09 18:13:52 +02:00
|
|
|
static bool ShouldIgnoreRotor( uint32_t id )
|
2016-11-12 18:28:46 +01:00
|
|
|
{
|
|
|
|
return std::find( vecRotorExceptions.begin(), vecRotorExceptions.end(), id ) != vecRotorExceptions.end();
|
|
|
|
}
|
2015-05-05 23:29:15 +02:00
|
|
|
|
2014-08-22 00:10:23 +02:00
|
|
|
static void* varVehicleRender = AddressByVersion<void*>(0x6D0E60, 0x6D1680, 0x70C0B0);
|
2014-08-04 14:30:16 +02:00
|
|
|
WRAPPER void CVehicle::Render() { VARJMP(varVehicleRender); }
|
2014-08-22 00:10:23 +02:00
|
|
|
static void* varIsLawEnforcementVehicle = AddressByVersion<void*>(0x6D2370, 0x6D2BA0, 0x70D8C0);
|
2014-08-04 14:30:16 +02:00
|
|
|
WRAPPER bool CVehicle::IsLawEnforcementVehicle() { VARJMP(varIsLawEnforcementVehicle); }
|
2014-05-30 20:14:47 +02:00
|
|
|
|
2016-11-12 18:28:46 +01:00
|
|
|
static int32_t random(int32_t from, int32_t to)
|
|
|
|
{
|
2017-03-09 00:53:03 +01:00
|
|
|
return from + ( Int32Rand() % (to-from) );
|
2016-11-12 18:28:46 +01:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
static RwObject* GetCurrentAtomicObject( RwFrame* frame )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RwObject* obj = nullptr;
|
|
|
|
RwFrameForAllObjects( frame, [&obj]( RwObject* object ) -> RwObject* {
|
|
|
|
if ( RpAtomicGetFlags(object) & rpATOMICRENDER )
|
|
|
|
{
|
|
|
|
obj = object;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return object;
|
|
|
|
} );
|
|
|
|
return obj;
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
static RwFrame* GetFrameFromName( RwFrame* topFrame, const char* name )
|
2014-08-12 22:30:37 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
class GetFramePredicate
|
2014-08-12 22:30:37 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
public:
|
|
|
|
RwFrame* foundFrame = nullptr;
|
2014-08-12 22:30:37 +02:00
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
GetFramePredicate( const char* name )
|
|
|
|
: m_name( name )
|
|
|
|
{
|
|
|
|
}
|
2014-08-12 22:30:37 +02:00
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
RwFrame* operator() ( RwFrame* frame )
|
|
|
|
{
|
|
|
|
if ( strcmp( m_name, GetFrameNodeName(frame) ) == 0 )
|
|
|
|
{
|
|
|
|
foundFrame = frame;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-04-02 18:59:08 +02:00
|
|
|
RwFrameForAllChildren( frame, *this );
|
2017-03-27 21:17:43 +02:00
|
|
|
return foundFrame != nullptr ? nullptr : frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const char* const m_name;
|
|
|
|
};
|
|
|
|
|
|
|
|
GetFramePredicate p( name );
|
2017-04-02 18:59:08 +02:00
|
|
|
RwFrameForAllChildren( topFrame, p );
|
2017-03-27 21:17:43 +02:00
|
|
|
return p.foundFrame;
|
2014-08-18 15:27:40 +02:00
|
|
|
}
|
|
|
|
|
2015-05-05 23:29:15 +02:00
|
|
|
void ReadRotorFixExceptions(const wchar_t* pPath)
|
|
|
|
{
|
2016-08-11 01:29:54 +02:00
|
|
|
const size_t SCRATCH_PAD_SIZE = 32767;
|
2017-03-23 11:30:06 +01:00
|
|
|
WideDelimStringReader reader( SCRATCH_PAD_SIZE );
|
2015-05-05 23:29:15 +02:00
|
|
|
|
2017-03-23 11:30:06 +01:00
|
|
|
GetPrivateProfileSectionW( L"RotorFixExceptions", reader.GetBuffer(), reader.GetSize(), pPath );
|
|
|
|
while ( const wchar_t* str = reader.GetString() )
|
2016-08-11 01:29:54 +02:00
|
|
|
{
|
2017-04-09 18:13:52 +02:00
|
|
|
uint32_t toList = wcstoul( str, nullptr, 0 );
|
2016-08-11 01:29:54 +02:00
|
|
|
if ( toList != 0 )
|
2016-11-12 18:28:46 +01:00
|
|
|
vecRotorExceptions.push_back( toList );
|
2015-05-05 23:29:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-18 15:27:40 +02:00
|
|
|
void CVehicle::SetComponentAtomicAlpha(RpAtomic* pAtomic, int nAlpha)
|
|
|
|
{
|
|
|
|
RpGeometry* pGeometry = RpAtomicGetGeometry(pAtomic);
|
|
|
|
pGeometry->flags |= rpGEOMETRYMODULATEMATERIALCOLOR;
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
RpGeometryForAllMaterials( pGeometry, [nAlpha] (RpMaterial* material) {
|
|
|
|
material->color.alpha = RwUInt8(nAlpha);
|
|
|
|
return material;
|
|
|
|
} );
|
2014-08-18 15:27:40 +02:00
|
|
|
}
|
|
|
|
|
2014-06-23 02:37:03 +02:00
|
|
|
bool CVehicle::CustomCarPlate_TextureCreate(CVehicleModelInfo* pModelInfo)
|
|
|
|
{
|
2016-03-12 14:18:24 +01:00
|
|
|
char PlateText[10];
|
2014-06-23 02:37:03 +02:00
|
|
|
const char* pOverrideText = pModelInfo->GetCustomCarPlateText();
|
|
|
|
|
|
|
|
if ( pOverrideText )
|
2016-03-11 21:11:35 +01:00
|
|
|
strcpy_s(PlateText, pOverrideText);
|
2014-06-23 02:37:03 +02:00
|
|
|
else
|
|
|
|
CCustomCarPlateMgr::GeneratePlateText(PlateText, 8);
|
|
|
|
|
|
|
|
PlateTexture = CCustomCarPlateMgr::CreatePlateTexture(PlateText, pModelInfo->m_nPlateType);
|
2014-06-23 14:54:36 +02:00
|
|
|
//PlateDesign = pModelInfo->m_nPlateType != -1 ? pModelInfo->m_nPlateType : CCustomCarPlateMgr::GetMapRegionPlateDesign();
|
|
|
|
if ( pModelInfo->m_nPlateType != -1 )
|
|
|
|
PlateDesign = pModelInfo->m_nPlateType;
|
|
|
|
else if ( IsLawEnforcementVehicle() )
|
|
|
|
PlateDesign = CCustomCarPlateMgr::GetMapRegionPlateDesign();
|
|
|
|
else
|
2017-03-27 21:17:43 +02:00
|
|
|
PlateDesign = random(0, 20) == 0 ? int8_t(random(0, 3)) : CCustomCarPlateMgr::GetMapRegionPlateDesign();
|
2014-06-23 02:37:03 +02:00
|
|
|
|
|
|
|
assert(PlateDesign >= 0 && PlateDesign < 3);
|
|
|
|
|
|
|
|
pModelInfo->m_plateText[0] = '\0';
|
|
|
|
pModelInfo->m_nPlateType = -1;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVehicle::CustomCarPlate_BeforeRenderingStart(CVehicleModelInfo* pModelInfo)
|
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
for ( ptrdiff_t i = 0; i < CCustomCarPlateMgr::NUM_MAX_PLATES; i++ )
|
2014-06-23 02:37:03 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( pModelInfo->m_apPlateMaterials[i] != nullptr )
|
2014-06-23 02:37:03 +02:00
|
|
|
{
|
|
|
|
RpMaterialSetTexture(pModelInfo->m_apPlateMaterials[i], PlateTexture);
|
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( pModelInfo->m_apPlateMaterials[CCustomCarPlateMgr::NUM_MAX_PLATES+i] != nullptr )
|
2014-06-23 02:37:03 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
CCustomCarPlateMgr::SetupMaterialPlatebackTexture(pModelInfo->m_apPlateMaterials[CCustomCarPlateMgr::NUM_MAX_PLATES+i], PlateDesign);
|
2014-06-23 02:37:03 +02:00
|
|
|
}
|
|
|
|
}
|
2017-03-27 21:17:43 +02:00
|
|
|
}
|
2014-06-23 02:37:03 +02:00
|
|
|
|
2014-05-30 20:14:47 +02:00
|
|
|
void CHeli::Render()
|
|
|
|
{
|
|
|
|
double dRotorsSpeed, dMovingRotorSpeed;
|
2016-11-12 18:28:46 +01:00
|
|
|
bool bDisplayRotors = !ShouldIgnoreRotor( m_nModelIndex );
|
|
|
|
bool bHasMovingRotor = m_pCarNode[13] != nullptr && bDisplayRotors;
|
|
|
|
bool bHasMovingRotor2 = m_pCarNode[15] != nullptr && bDisplayRotors;
|
2014-05-30 20:14:47 +02:00
|
|
|
|
2014-08-03 15:38:53 +02:00
|
|
|
m_nTimeTillWeNeedThisCar = CTimer::m_snTimeInMilliseconds + 3000;
|
2014-05-30 20:14:47 +02:00
|
|
|
|
|
|
|
if ( m_fRotorSpeed > 0.0 )
|
2016-11-12 18:28:46 +01:00
|
|
|
dRotorsSpeed = std::min(1.7 * (1.0/0.22) * m_fRotorSpeed, 1.5);
|
2014-05-30 20:14:47 +02:00
|
|
|
else
|
|
|
|
dRotorsSpeed = 0.0;
|
|
|
|
|
|
|
|
dMovingRotorSpeed = dRotorsSpeed - 0.4;
|
|
|
|
if ( dMovingRotorSpeed < 0.0 )
|
|
|
|
dMovingRotorSpeed = 0.0;
|
|
|
|
|
2016-11-12 18:28:46 +01:00
|
|
|
int nStaticRotorAlpha = static_cast<int>(std::min((1.5-dRotorsSpeed) * 255.0, 255.0));
|
|
|
|
int nMovingRotorAlpha = static_cast<int>(std::min(dMovingRotorSpeed * 175.0, 175.0));
|
2014-05-30 20:14:47 +02:00
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[12] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[12] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2014-06-03 02:10:03 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingRotor ? nStaticRotorAlpha : 255);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[14] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[14] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2014-06-03 02:10:03 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingRotor2 ? nStaticRotorAlpha : 255);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[13] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[13] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2015-05-05 23:29:15 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingRotor ? nMovingRotorAlpha : 0);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[15] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[15] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2015-05-05 23:29:15 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingRotor2 ? nMovingRotorAlpha : 0);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CEntity::Render();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPlane::Render()
|
|
|
|
{
|
|
|
|
double dRotorsSpeed, dMovingRotorSpeed;
|
2016-11-12 18:28:46 +01:00
|
|
|
bool bDisplayRotors = !ShouldIgnoreRotor( m_nModelIndex );
|
|
|
|
bool bHasMovingProp = m_pCarNode[13] != nullptr && bDisplayRotors;
|
|
|
|
bool bHasMovingProp2 = m_pCarNode[15] != nullptr && bDisplayRotors;
|
2014-05-30 20:14:47 +02:00
|
|
|
|
2014-08-03 15:38:53 +02:00
|
|
|
m_nTimeTillWeNeedThisCar = CTimer::m_snTimeInMilliseconds + 3000;
|
2014-05-30 20:14:47 +02:00
|
|
|
|
|
|
|
if ( m_fPropellerSpeed > 0.0 )
|
2016-11-12 18:28:46 +01:00
|
|
|
dRotorsSpeed = std::min(1.7 * (1.0/0.31) * m_fPropellerSpeed, 1.5);
|
2014-05-30 20:14:47 +02:00
|
|
|
else
|
|
|
|
dRotorsSpeed = 0.0;
|
|
|
|
|
|
|
|
dMovingRotorSpeed = dRotorsSpeed - 0.4;
|
|
|
|
if ( dMovingRotorSpeed < 0.0 )
|
|
|
|
dMovingRotorSpeed = 0.0;
|
|
|
|
|
2016-11-12 18:28:46 +01:00
|
|
|
int nStaticRotorAlpha = static_cast<int>(std::min((1.5-dRotorsSpeed) * 255.0, 255.0));
|
|
|
|
int nMovingRotorAlpha = static_cast<int>(std::min(dMovingRotorSpeed * 175.0, 175.0));
|
2014-05-30 20:14:47 +02:00
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[12] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[12] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2014-06-04 16:12:53 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingProp ? nStaticRotorAlpha : 255);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[14] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[14] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2014-06-04 16:12:53 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingProp2 ? nStaticRotorAlpha : 255);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[13] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[13] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2015-05-05 23:29:15 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingProp ? nMovingRotorAlpha : 0);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[15] != nullptr )
|
2014-05-30 20:14:47 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
RpAtomic* pOutAtomic = (RpAtomic*)GetCurrentAtomicObject( m_pCarNode[15] );
|
|
|
|
if ( pOutAtomic != nullptr )
|
2015-05-05 23:29:15 +02:00
|
|
|
SetComponentAtomicAlpha(pOutAtomic, bHasMovingProp2 ? nMovingRotorAlpha : 0);
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CVehicle::Render();
|
2014-08-11 22:44:57 +02:00
|
|
|
}
|
|
|
|
|
2014-08-12 22:43:17 +02:00
|
|
|
void CPlane::Fix_SilentPatch()
|
|
|
|
{
|
|
|
|
// Reset bouncing panels
|
2016-04-22 21:55:15 +02:00
|
|
|
// No reset on Vortex
|
|
|
|
for ( ptrdiff_t i = m_nModelIndex == 539 ? 1 : 0; i < 3; i++ )
|
2014-08-12 22:43:17 +02:00
|
|
|
{
|
|
|
|
m_aBouncingPanel[i].m_nNodeIndex = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-11 22:44:57 +02:00
|
|
|
void CAutomobile::Fix_SilentPatch()
|
|
|
|
{
|
2014-08-12 22:30:37 +02:00
|
|
|
ResetFrames();
|
|
|
|
|
2014-08-11 22:44:57 +02:00
|
|
|
// Reset bouncing panels
|
2016-04-22 21:55:15 +02:00
|
|
|
for ( ptrdiff_t i = (m_nModelIndex == 525 && m_pCarNode[21]) || (m_nModelIndex == 531 && m_pCarNode[17]) ? 1 : 0; i < 3; i++ )
|
2014-08-11 22:44:57 +02:00
|
|
|
{
|
|
|
|
// Towtruck/Tractor fix
|
|
|
|
m_aBouncingPanel[i].m_nNodeIndex = -1;
|
|
|
|
}
|
2014-08-12 22:30:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CAutomobile::ResetFrames()
|
|
|
|
{
|
|
|
|
RpClump* pOrigClump = reinterpret_cast<RpClump*>(ms_modelInfoPtrs[m_nModelIndex]->pRwObject);
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( pOrigClump != nullptr )
|
2014-08-12 22:30:37 +02:00
|
|
|
{
|
|
|
|
// Instead of setting frame rotation to (0,0,0) like R* did, obtain the original frame matrix from CBaseNodelInfo clump
|
2016-04-22 21:55:15 +02:00
|
|
|
for ( ptrdiff_t i = 8; i < 25; i++ )
|
2014-08-12 22:30:37 +02:00
|
|
|
{
|
2017-03-27 21:17:43 +02:00
|
|
|
if ( m_pCarNode[i] != nullptr )
|
2014-08-12 22:30:37 +02:00
|
|
|
{
|
|
|
|
// Find a frame in CBaseModelInfo object
|
2017-03-27 21:17:43 +02:00
|
|
|
RwFrame* origFrame = GetFrameFromName( RpClumpGetFrame(pOrigClump), GetFrameNodeName(m_pCarNode[i]) );
|
|
|
|
if ( origFrame != nullptr )
|
2014-08-12 22:30:37 +02:00
|
|
|
{
|
|
|
|
// Found a frame, reset it
|
2017-03-27 21:17:43 +02:00
|
|
|
*RwFrameGetMatrix(m_pCarNode[i]) = *RwFrameGetMatrix(origFrame);
|
2014-08-12 22:30:37 +02:00
|
|
|
RwMatrixUpdate(RwFrameGetMatrix(m_pCarNode[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-30 20:14:47 +02:00
|
|
|
}
|