Files
GTASource/game/Vehicles/vehiclestorage.cpp

328 lines
11 KiB
C++
Raw Normal View History

2025-02-23 17:40:52 +08:00
/////////////////////////////////////////////////////////////////////////////////
//
// FILE : vehiclestorage.cpp
// PURPOSE : Stuff having to do with taking vehicles off the map and storing them in a small structure.
// Later on the vehicle can be recreated from this structure.
// AUTHOR : Obbe.
// CREATED : 30-9-05
//
/////////////////////////////////////////////////////////////////////////////////
#include "vehicles\vehiclestorage.h"
#include "vehicles\vehicle.h"
#include "scene\world\gameWorld.h"
#include "modelinfo\vehiclemodelinfo.h"
#include "network\live\NetworkTelemetry.h"
#include "stats\MoneyInterface.h"
#include "streaming\streaming.h"
#include "vehicles/Automobile.h"
#include "vehicles\vehiclefactory.h"
#include "VehicleAi\task\TaskVehiclePlayer.h"
#include "fwscene\world\WorldLimits.h"
#define FRONTCOMPR (100.0f)
CStoredVehicleVariations::CStoredVehicleVariations() :
m_color1(0),
m_color2(0),
m_color3(0),
m_color4(0),
m_smokeColR(0),
m_smokeColG(0),
m_smokeColB(0),
m_neonColR(0),
m_neonColG(0),
m_neonColB(0),
m_neonFlags(0),
m_windowTint(0),
m_wheelType(VWT_SPORT),
m_kitIdx(INVALID_VEHICLE_KIT_INDEX)
{
for (s32 i = 0; i < VMT_MAX; ++i)
{
m_mods[i] = INVALID_MOD;
}
m_modVariation[0] = false;
m_modVariation[1] = false;
}
void CStoredVehicleVariations::StoreVariations(const CVehicle* pVeh)
{
if (!pVeh)
return;
const CVehicleVariationInstance& VehicleVariationInstance = pVeh->GetVariationInstance();
m_kitIdx = VehicleVariationInstance.GetKitIndex();
for (u32 mod_loop = 0; mod_loop < VMT_MAX; mod_loop++)
{
m_mods[mod_loop] = VehicleVariationInstance.GetModIndex(static_cast<eVehicleModType>(mod_loop));
}
m_color1 = VehicleVariationInstance.GetColor1();
m_color2 = VehicleVariationInstance.GetColor2();
m_color3 = VehicleVariationInstance.GetColor3();
m_color4 = VehicleVariationInstance.GetColor4();
m_color5 = VehicleVariationInstance.GetColor5();
m_color6 = VehicleVariationInstance.GetColor6();
m_smokeColR = VehicleVariationInstance.GetSmokeColorR();
m_smokeColG = VehicleVariationInstance.GetSmokeColorG();
m_smokeColB = VehicleVariationInstance.GetSmokeColorB();
m_neonColR = VehicleVariationInstance.GetNeonColour().GetRed();
m_neonColG = VehicleVariationInstance.GetNeonColour().GetGreen();
m_neonColB = VehicleVariationInstance.GetNeonColour().GetBlue();
m_neonFlags = 0;
if(VehicleVariationInstance.IsNeonLOn())
m_neonFlags |= 1;
if(VehicleVariationInstance.IsNeonROn())
m_neonFlags |= 2;
if(VehicleVariationInstance.IsNeonFOn())
m_neonFlags |= 4;
if(VehicleVariationInstance.IsNeonBOn())
m_neonFlags |= 8;
m_windowTint = VehicleVariationInstance.GetWindowTint();
m_wheelType = (u8)VehicleVariationInstance.GetWheelType(pVeh);
m_modVariation[0] = VehicleVariationInstance.HasVariation(0);
m_modVariation[1] = VehicleVariationInstance.HasVariation(1);
}
bool CStoredVehicleVariations::IsToggleModOn(eVehicleModType modSlot) const
{
if (Verifyf(modSlot >= VMT_TOGGLE_MODS && modSlot < VMT_MISC_MODS, "CStoredVehicleVariations::IsToggleModOn - Mod type %d is not a toggle mod", modSlot))
{
return m_mods[modSlot] != INVALID_MOD;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : StoreVehicle
// PURPOSE : Stores one vehicle into a structure (all the info needed to recreate the vehicle)
/////////////////////////////////////////////////////////////////////////////////
void CStoredVehicle::StoreVehicle(CVehicle *pVeh)
{
if (Verifyf(pVeh, "CStoredVehicle::StoreVehicle - vehicle pointer is NULL"))
{
const Vector3 vVehPosition = VEC3V_TO_VECTOR3(pVeh->GetTransform().GetPosition());
// Make sure coordinates are on the map. (We got a bug with nan coordinates being saved)
Assert(vVehPosition.x > WORLDLIMITS_XMIN);
Assert(vVehPosition.x < WORLDLIMITS_XMAX);
Assert(vVehPosition.y > WORLDLIMITS_YMIN);
Assert(vVehPosition.y < WORLDLIMITS_YMAX);
m_variation.StoreVariations(pVeh);
// m_ModelIndex = static_cast<u16>(pVeh->GetModelIndex());
if (Verifyf(pVeh->GetBaseModelInfo(), "CStoredVehicle::StoreVehicle - failed to get BaseModelInfo for vehicle"))
{
SetModelHashKey(pVeh->GetBaseModelInfo()->GetModelNameHash());
}
else
{
m_ModelHashKey = 0;
}
m_CoorX = vVehPosition.x;
m_CoorY = vVehPosition.y;
m_CoorZ = vVehPosition.z;
Vector3 vecForward(VEC3V_TO_VECTOR3(pVeh->GetTransform().GetB()));
m_iFrontX = (s8)(vecForward.x * FRONTCOMPR);
m_iFrontY = (s8)(vecForward.y * FRONTCOMPR);
m_iFrontZ = (s8)(vecForward.z * FRONTCOMPR);
m_LiveryId = pVeh->GetLiveryId();
m_Livery2Id= pVeh->GetLivery2Id();
m_nDisableExtras = pVeh->m_nDisableExtras;
m_bInInterior = pVeh->m_nFlags.bInMloRoom;
m_bNotDamagedByBullets = pVeh->m_nPhysicalFlags.bNotDamagedByBullets;
m_bNotDamagedByFlames = pVeh->m_nPhysicalFlags.bNotDamagedByFlames;
m_bIgnoresExplosions = pVeh->m_nPhysicalFlags.bIgnoresExplosions;
m_bNotDamagedByCollisions = pVeh->m_nPhysicalFlags.bNotDamagedByCollisions;
m_bNotDamagedByMelee = pVeh->m_nPhysicalFlags.bNotDamagedByMelee;
m_bTyresDontBurst = pVeh->m_nVehicleFlags.bTyresDontBurst;
if(pVeh->GetVehicleAudioEntity())
{
m_HornSoundIndex = pVeh->GetVehicleAudioEntity()->GetHornSoundIdx();
m_AudioEngineHealth = pVeh->GetVehicleAudioEntity()->GetFakeEngineHealth();
m_AudioBodyHealth = pVeh->GetVehicleAudioEntity()->GetFakeBodyHealth();
}
else
{
m_HornSoundIndex = -1;
m_AudioEngineHealth = -1;
m_AudioBodyHealth = -1;
}
// License plate
CCustomShaderEffectVehicle *pShaderEffectVehicle = static_cast<CCustomShaderEffectVehicle*>(pVeh->GetDrawHandler().GetShaderEffect());
memcpy(m_LicencePlateText, pShaderEffectVehicle->GetLicensePlateText(), CCustomShaderEffectVehicle::LICENCE_PLATE_LETTERS_MAX);
Assertf( (pShaderEffectVehicle->GetLicensePlateTexIndex() >= MIN_INT8) && (pShaderEffectVehicle->GetLicensePlateTexIndex() <= MAX_INT8), "CStoredVehicle::StoreVehicle - expected LicensePlateTexIndex to fit within an int8");
m_plateTexIndex = (s8) pShaderEffectVehicle->GetLicensePlateTexIndex();
m_bUsed = true;
m_collisionTestResult.Reset();
}
}
void CStoredVehicle::SetModelHashKey(u32 modelHashKey)
{
m_ModelHashKey = modelHashKey;
m_hashedModelHashKey = atDataHash(&m_ModelHashKey, sizeof(m_ModelHashKey));
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : RestoreVehicle
// PURPOSE : Restores one vehicle from a little struct
/////////////////////////////////////////////////////////////////////////////////
CVehicle *CStoredVehicle::RestoreVehicle()
{
CVehicle *pNewVehicle;
fwModelId vehicleModelId;
if (atDataHash(&m_ModelHashKey,sizeof(m_ModelHashKey)) != m_hashedModelHashKey)
{
vehicleDisplayf("* restore vehicle check failed *");
MoneyInterface::MemoryTampering( true );
CNetworkTelemetry::AppendGarageTamper(m_ModelHashKey);
Assertf(false, "Stored vehicle was not set using SetModelHashKey() call");
return NULL;
}
CModelInfo::GetBaseModelInfoFromHashKey(m_ModelHashKey, &vehicleModelId); // ignores return value
// fwModelId modelId((u32)m_ModelIndex);
Assert(CModelInfo::HaveAssetsLoaded(vehicleModelId));
if (CModelInfo::HaveAssetsLoaded(vehicleModelId))
{
// Make sure coordinates are on the map. (We got a bug with nan coordinates being saved)
Assert(m_CoorX > WORLDLIMITS_XMIN);
Assert(m_CoorX < WORLDLIMITS_XMAX);
Assert(m_CoorY > WORLDLIMITS_YMIN);
Assert(m_CoorY < WORLDLIMITS_YMAX);
Matrix34 tempMat;
tempMat.Identity();
tempMat.d = Vector3(m_CoorX, m_CoorY, m_CoorZ);
float FrontX = m_iFrontX / FRONTCOMPR;
float FrontY = m_iFrontY / FRONTCOMPR;
float FrontZ = m_iFrontZ / FRONTCOMPR;
tempMat.b.x = FrontX; // Forward
tempMat.b.y = FrontY;
tempMat.b.z = FrontZ;
tempMat.b.Normalize();
tempMat.a.x = FrontY; // Side
tempMat.a.y = -FrontX;
tempMat.a.z = 0.0f;
tempMat.a.Normalize();
tempMat.c.Cross(tempMat.a, tempMat.b); // Up
tempMat.c.Normalize();
pNewVehicle = CVehicleFactory::GetFactory()->Create(vehicleModelId, ENTITY_OWNEDBY_POPULATION, POPTYPE_RANDOM_AMBIENT, &tempMat);
if(pNewVehicle)
{
pNewVehicle->SetIsAbandoned();
pNewVehicle->m_nDisableExtras = m_nDisableExtras;
// probably need to call some code to switch off extra fragment groups
pNewVehicle->m_nVehicleFlags.bFreebies = false; // no freebies left in here
pNewVehicle->m_nVehicleFlags.bHasBeenOwnedByPlayer = true; // So that player can take it without commiting crime
pNewVehicle->m_nVehicleFlags.bCarNeedsToBeHotwired = false;
pNewVehicle->SetCarDoorLocks(CARLOCK_UNLOCKED);// Make sure the car isn't locked (like police cars)
pNewVehicle->m_nVehicleFlags.bTyresDontBurst = m_bTyresDontBurst;
pNewVehicle->m_nPhysicalFlags.bNotDamagedByBullets = m_bNotDamagedByBullets;
pNewVehicle->m_nPhysicalFlags.bNotDamagedByFlames = m_bNotDamagedByFlames;
pNewVehicle->m_nPhysicalFlags.bIgnoresExplosions = m_bIgnoresExplosions;
pNewVehicle->m_nPhysicalFlags.bNotDamagedByCollisions = m_bNotDamagedByCollisions;
pNewVehicle->m_nPhysicalFlags.bNotDamagedByMelee = m_bNotDamagedByMelee;
CCustomShaderEffectVehicle *pShaderEffectVehicle = static_cast<CCustomShaderEffectVehicle*>(pNewVehicle->GetDrawHandler().GetShaderEffect());
pShaderEffectVehicle->SetLicensePlateText( (const char*)m_LicencePlateText );
pShaderEffectVehicle->SetLicensePlateTexIndex(m_plateTexIndex);
pNewVehicle->SwitchEngineOff();
pNewVehicle->SetVariationInstance(m_variation);
pNewVehicle->SetLiveryId(m_LiveryId);
pNewVehicle->SetLivery2Id(m_Livery2Id);
pNewVehicle->UpdateBodyColourRemapping(); // let shaders know, that body colours changed
CInteriorInst* pDestInteriorInst = 0;
s32 destRoomIdx = -1;
bool setWaitForAllCollisionsBeforeProbe = false;
CAutomobile::PlaceOnRoadProperly((CAutomobile*)pNewVehicle, &tempMat, pDestInteriorInst, destRoomIdx, setWaitForAllCollisionsBeforeProbe, vehicleModelId.GetModelIndex(), NULL, false, NULL, NULL, 0);
fwInteriorLocation loc = CGameWorld::OUTSIDE;
if (pDestInteriorInst && pDestInteriorInst->CanReceiveObjects()){
loc = CInteriorInst::CreateLocation(pDestInteriorInst, destRoomIdx);
}
CGameWorld::Add(pNewVehicle, loc);
if (m_bInInterior){
pNewVehicle->GetPortalTracker()->ScanUntilProbeTrue();
}
pNewVehicle->Fix();
pNewVehicle->SetIsFixedWaitingForCollision(true);
if(pNewVehicle->GetVehicleAudioEntity())
{
pNewVehicle->GetVehicleAudioEntity()->SetHornSoundIdx(m_HornSoundIndex);
pNewVehicle->GetVehicleAudioEntity()->SetFakeEngineHealth(m_AudioEngineHealth);
pNewVehicle->GetVehicleAudioEntity()->SetFakeBodyHealth(m_AudioBodyHealth);
}
}
return (pNewVehicle);
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : Clear
// PURPOSE : Empties this stored vehicle
/////////////////////////////////////////////////////////////////////////////////
void CStoredVehicle::Clear()
{
m_bUsed = false;
m_bInteriorRequired = false;
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : IsUsed
// PURPOSE : Returns whether there is a vehicle in this storedvehicle
/////////////////////////////////////////////////////////////////////////////////
bool CStoredVehicle::IsUsed()
{
return m_bUsed;
}